Coverage Report
Generated on Fri, 17 Nov 2023 16:44:20 CST with gocov-html
Report Overview
github.com/wfusion/gofusion/async 68.8% 232/337
github.com/wfusion/gofusion/cache 76.9% 223/290
github.com/wfusion/gofusion/common/constant 75.0% 3/4
github.com/wfusion/gofusion/common/di 69.0% 40/58
github.com/wfusion/gofusion/common/env 61.9% 13/21
github.com/wfusion/gofusion/common/infra/drivers/mongo 89.1% 41/46
github.com/wfusion/gofusion/common/infra/drivers/orm 75.3% 55/73
github.com/wfusion/gofusion/common/infra/drivers/orm/idgen 87.5% 21/24
github.com/wfusion/gofusion/common/infra/drivers/redis 47.1% 32/68
github.com/wfusion/gofusion/common/utils 56.4% 514/912
github.com/wfusion/gofusion/common/utils/cipher 85.6% 357/417
github.com/wfusion/gofusion/common/utils/clone 37.3% 281/753
github.com/wfusion/gofusion/common/utils/cmp 23.1% 33/143
github.com/wfusion/gofusion/common/utils/compress 73.7% 101/137
github.com/wfusion/gofusion/common/utils/encode 84.3% 167/198
github.com/wfusion/gofusion/common/utils/inspect 67.7% 67/99
github.com/wfusion/gofusion/common/utils/serialize 66.7% 70/105
github.com/wfusion/gofusion/config 79.5% 345/434
github.com/wfusion/gofusion/context 75.0% 87/116
github.com/wfusion/gofusion/cron 76.8% 251/327
github.com/wfusion/gofusion/db 51.8% 307/593
github.com/wfusion/gofusion/db/callbacks 44.0% 70/159
github.com/wfusion/gofusion/db/plugins 61.0% 407/667
github.com/wfusion/gofusion/db/softdelete 59.0% 72/122
github.com/wfusion/gofusion/http 68.3% 426/624
github.com/wfusion/gofusion/http/consts 88.9% 8/9
github.com/wfusion/gofusion/http/gracefully 37.8% 88/233
github.com/wfusion/gofusion/http/middleware 53.3% 97/182
github.com/wfusion/gofusion/http/parser 47.4% 144/304
github.com/wfusion/gofusion/i18n 57.0% 49/86
github.com/wfusion/gofusion/internal/configor 59.3% 147/248
github.com/wfusion/gofusion/internal/util/payload 60.2% 127/211
github.com/wfusion/gofusion/lock 80.9% 190/235
github.com/wfusion/gofusion/log 72.6% 162/223
github.com/wfusion/gofusion/log/customlogger 59.2% 287/485
github.com/wfusion/gofusion/log/encoder 100.0% 12/12
github.com/wfusion/gofusion/metrics 72.5% 190/262
github.com/wfusion/gofusion/mongo 76.6% 108/141
github.com/wfusion/gofusion/mq 62.1% 486/782
github.com/wfusion/gofusion/redis 23.4% 107/457
github.com/wfusion/gofusion/routine 48.4% 352/728

This coverage report has been generated with the following command:

gocov test github.com/wfusion/gofusion/async github.com/wfusion/gofusion/cache github.com/wfusion/gofusion/common/constant github.com/wfusion/gofusion/common/di github.com/wfusion/gofusion/common/env github.com/wfusion/gofusion/common/infra/drivers/mongo github.com/wfusion/gofusion/common/infra/drivers/orm github.com/wfusion/gofusion/common/infra/drivers/orm/idgen github.com/wfusion/gofusion/common/infra/drivers/redis github.com/wfusion/gofusion/common/utils github.com/wfusion/gofusion/common/utils/cipher github.com/wfusion/gofusion/common/utils/clone github.com/wfusion/gofusion/common/utils/cmp github.com/wfusion/gofusion/common/utils/compress github.com/wfusion/gofusion/common/utils/encode github.com/wfusion/gofusion/common/utils/inspect github.com/wfusion/gofusion/common/utils/serialize github.com/wfusion/gofusion/config github.com/wfusion/gofusion/context github.com/wfusion/gofusion/cron github.com/wfusion/gofusion/db github.com/wfusion/gofusion/db/callbacks github.com/wfusion/gofusion/db/plugins github.com/wfusion/gofusion/db/softdelete github.com/wfusion/gofusion/http github.com/wfusion/gofusion/http/consts github.com/wfusion/gofusion/http/gracefully github.com/wfusion/gofusion/http/middleware github.com/wfusion/gofusion/http/parser github.com/wfusion/gofusion/i18n github.com/wfusion/gofusion/internal/configor github.com/wfusion/gofusion/internal/util/payload github.com/wfusion/gofusion/lock github.com/wfusion/gofusion/log github.com/wfusion/gofusion/log/customlogger github.com/wfusion/gofusion/log/encoder github.com/wfusion/gofusion/metrics github.com/wfusion/gofusion/mongo github.com/wfusion/gofusion/mq github.com/wfusion/gofusion/redis github.com/wfusion/gofusion/routine | gocov-html 
Package Overview: github.com/wfusion/gofusion/async 68.8%

Please select a function to see what's left for testing.

Construct(...) github.com/wfusion/gofusion/async/construct.go 100.0% 7/7
asynqConsumer.shutdown(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 4/4
@212:27(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 3/3
asynqConsumer.adaptAsynqHandlerFunc(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 2/2
init(...) github.com/wfusion/gofusion/async/construct.go 100.0% 1/1
asynqConsumer.unformatTaskName(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 1/1
@125:9(...) github.com/wfusion/gofusion/async/types.go 100.0% 1/1
defaultQueue(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 1/1
Queue(...) github.com/wfusion/gofusion/async/types.go 100.0% 1/1
asynqConsumer.gatewayMiddleware(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 1/1
asynqRedisConnOpt.MakeRedisClient(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 1/1
@122:9(...) github.com/wfusion/gofusion/async/types.go 100.0% 1/1
Args(...) github.com/wfusion/gofusion/async/types.go 100.0% 1/1
asynqConsumer.format(...) github.com/wfusion/gofusion/async/log.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/async/construct.go 100.0% 1/1
formatTaskName(...) github.com/wfusion/gofusion/async/asynq.go 100.0% 1/1
@127:9(...) github.com/wfusion/gofusion/async/construct.go 100.0% 1/1
@34:9(...) github.com/wfusion/gofusion/async/construct.go 92.3% 12/13
wrapParams(...) github.com/wfusion/gofusion/async/utils.go 90.0% 9/10
unwrapParams(...) github.com/wfusion/gofusion/async/utils.go 90.0% 9/10
newAsynqConsumer(...) github.com/wfusion/gofusion/async/asynq.go 89.3% 25/28
asynqProducer.Go(...) github.com/wfusion/gofusion/async/asynq.go 88.9% 16/18
asynqConsumer.info(...) github.com/wfusion/gofusion/async/log.go 85.7% 6/7
asynqConsumer.Handle(...) github.com/wfusion/gofusion/async/asynq.go 85.0% 17/20
asynqConsumer.Start(...) github.com/wfusion/gofusion/async/asynq.go 83.3% 5/6
asynqProducer.Goc(...) github.com/wfusion/gofusion/async/asynq.go 82.4% 14/17
addInstance(...) github.com/wfusion/gofusion/async/construct.go 80.0% 24/30
P(...) github.com/wfusion/gofusion/async/construct.go 80.0% 8/10
C(...) github.com/wfusion/gofusion/async/construct.go 80.0% 8/10
@230:9(...) github.com/wfusion/gofusion/async/asynq.go 80.0% 4/5
asynqProducer.newTask(...) github.com/wfusion/gofusion/async/asynq.go 80.0% 4/5
asynqProducer.Send(...) github.com/wfusion/gofusion/async/asynq.go 75.0% 6/8
asynqConsumer.HandleFunc(...) github.com/wfusion/gofusion/async/asynq.go 66.7% 10/15
setParams(...) github.com/wfusion/gofusion/async/utils.go 66.7% 8/12
newAsynqProducer(...) github.com/wfusion/gofusion/async/asynq.go 66.7% 6/9
asynqProducer.parseOption(...) github.com/wfusion/gofusion/async/asynq.go 60.0% 12/20
asynqConsumer.debug(...) github.com/wfusion/gofusion/async/log.go 0.0% 0/7
asynqConsumer.warn(...) github.com/wfusion/gofusion/async/log.go 0.0% 0/7
asynqConsumer.Serve(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/6
@81:40(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/4
asynqConsumer.Use(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/2
@220:9(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/2
asynqConsumer.adaptMiddleware(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
@222:28(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
task.ID(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
task.Name(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
task.Payload(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
task.RawMessage(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
TaskID(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@119:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@115:5(...) github.com/wfusion/gofusion/async/construct.go 0.0% 0/1
asynqConsumer.adaptRouterHandlerFunc(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
Delay(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@241:9(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
MaxRetry(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@128:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
Deadline(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@131:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
Timeout(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@134:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
asynqConsumer.newTask(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
@137:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
DelayAt(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@140:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
Retention(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@143:9(...) github.com/wfusion/gofusion/async/types.go 0.0% 0/1
@91:29(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
asynqConsumer.newAsynqTask(...) github.com/wfusion/gofusion/async/asynq.go 0.0% 0/1
@94:5(...) github.com/wfusion/gofusion/async/construct.go 0.0% 0/1
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

24
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
25
        opt := utils.ApplyOptions[config.InitOption](opts...)
26
        optU := utils.ApplyOptions[useOption](opts...)
27
        if opt.AppName == "" {
28
                opt.AppName = optU.appName
29
        }
30
31
        for name, conf := range confs {
32
                addInstance(ctx, name, conf, opt)
33
        }
34
        return func() {
35
                locker.Lock()
36
                defer locker.Unlock()
37
38
                pid := syscall.Getpid()
39
                app := config.Use(opt.AppName).AppName()
40
                if consumers != nil {
41
                        for name, router := range consumers[opt.AppName] {
42
                                log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentAsync, name)
43
                                if err := router.shutdown(); err == nil {
44
                                        log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentAsync, name)
45
                                } else {
46
                                        log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentAsync, name, err)
47
                                }
48
                        }
49
                        delete(consumers, opt.AppName)
50
                }
51
52
                if producers != nil {
53
                        producers[opt.AppName] = make(map[string]Producable, len(producers))
54
                }
55
        }
56
}
func asynqConsumer.shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

203
func (a *asynqConsumer) shutdown() (err error) {
204
        if a.consumer != nil {
205
                _, catchErr := utils.Catch(a.consumer.Shutdown)
206
                err = multierr.Append(err, errors.Cause(catchErr))
207
        }
208
        return
209
}
func @212:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

212
func(ctx context.Context, raw *asynq.Task) (err error) {
213
                taskName := a.unformatTaskName(raw.Type())
214
                inspect.SetField(raw, asyncqTaskTypenameField, taskName)
215
                return next.ProcessTask(ctx, raw)
216
        }
func asynqConsumer.adaptAsynqHandlerFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

228
func (a *asynqConsumer) adaptAsynqHandlerFunc(h any, typ reflect.Type, embed bool) asynq.HandlerFunc {
229
        fn := utils.WrapFunc1[error](h)
230
        return func(ctx context.Context, task *asynq.Task) (err error) {
231
                ctx, data, _, err := pd.Unseal(task.Payload(), pd.Type(typ))
232
                if err != nil {
233
                        return
234
                }
235
                params := unwrapParams(typ, embed, data)
236
                return fn(append([]any{ctx}, params...)...)
237
        }
238
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

164
func init() {
165
        config.AddComponent(config.ComponentAsync, Construct)
166
}
func asynqConsumer.unformatTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

246
func (a *asynqConsumer) unformatTaskName(taskName string) (result string) {
247
        return strings.TrimPrefix(taskName, fmt.Sprintf("%s:async:", config.Use(a.appName).AppName()))
248
}
func @125:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

125
func(o *produceOption) { o.queue = queue }
func defaultQueue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

422
func defaultQueue(appName string) (result string) {
423
        return fmt.Sprintf("%s:async", config.Use(appName).AppName())
424
}
func Queue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

124
func Queue(queue string) utils.OptionFunc[produceOption] {
125
        return func(o *produceOption) { o.queue = queue }
126
}
func asynqConsumer.gatewayMiddleware
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

211
func (a *asynqConsumer) gatewayMiddleware(next asynq.Handler) asynq.Handler {
212
        return asynq.HandlerFunc(func(ctx context.Context, raw *asynq.Task) (err error) {
213
                taskName := a.unformatTaskName(raw.Type())
214
                inspect.SetField(raw, asyncqTaskTypenameField, taskName)
215
                return next.ProcessTask(ctx, raw)
216
        })
217
}
func asynqRedisConnOpt.MakeRedisClient
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

416
func (a *asynqRedisConnOpt) MakeRedisClient() any { return a.UniversalClient }
func @122:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

122
func(o *produceOption) { o.args = append(o.args, args...) }
func Args
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

121
func Args(args ...any) utils.OptionFunc[produceOption] {
122
        return func(o *produceOption) { o.args = append(o.args, args...) }
123
}
func asynqConsumer.format
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/log.go:

48
func (a *asynqConsumer) format(src string) (dst string) {
49
        return fmt.Sprintf("%v [Gofusion] %s %s asynq %s",
50
                syscall.Getpid(), config.ComponentAsync, a.n, src)
51
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

126
func AppName(name string) utils.OptionFunc[useOption] {
127
        return func(o *useOption) {
128
                o.appName = name
129
        }
130
}
func formatTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

418
func formatTaskName(appName, taskName string) (result string) {
419
        return fmt.Sprintf("%s:async:%s", config.Use(appName).AppName(), taskName)
420
}
func @127:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

127
func(o *useOption) {
128
                o.appName = name
129
        }
func @34:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

34
func() {
35
                locker.Lock()
36
                defer locker.Unlock()
37
38
                pid := syscall.Getpid()
39
                app := config.Use(opt.AppName).AppName()
40
                if consumers != nil {
41
                        for name, router := range consumers[opt.AppName] {
42
                                log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentAsync, name)
43
                                if err := router.shutdown(); err == nil {
44
                                        log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentAsync, name)
45
                                } else {
46
                                        log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentAsync, name, err)
47
                                }
48
                        }
49
                        delete(consumers, opt.AppName)
50
                }
51
52
                if producers != nil {
53
                        producers[opt.AppName] = make(map[string]Producable, len(producers))
54
                }
55
        }
func wrapParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/utils.go:

8
func wrapParams(fn any) (argType reflect.Type, embed bool) {
9
        typ := reflect.TypeOf(fn)
10
11
        inLength := typ.NumIn()
12
        if inLength == 1 {
13
                return
14
        }
15
        if inLength == 2 {
16
                return typ.In(1), false
17
        }
18
19
        fields := make([]reflect.StructField, 0, inLength)
20
        for i := 1; i < inLength; i++ {
21
                fields = append(fields, reflect.StructField{
22
                        Name:      fmt.Sprintf("Arg%X", i+1),
23
                        PkgPath:   "",
24
                        Type:      typ.In(i),
25
                        Tag:       "",
26
                        Offset:    0,
27
                        Index:     nil,
28
                        Anonymous: false,
29
                })
30
        }
31
32
        return reflect.StructOf(fields), true
33
}
func unwrapParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/utils.go:

35
func unwrapParams(typ reflect.Type, embed bool, arg any) (params []any) {
36
        if typ == nil {
37
                return
38
        }
39
40
        if !embed {
41
                return []any{arg}
42
        }
43
44
        argVal := reflect.Indirect(reflect.ValueOf(arg))
45
        num := argVal.Type().NumField()
46
        params = make([]any, 0, num)
47
        for i := 0; i < num; i++ {
48
                params = append(params, argVal.Field(i).Interface())
49
        }
50
51
        return
52
}
func newAsynqConsumer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

47
func newAsynqConsumer(ctx context.Context, appName, name string, conf *Conf) Consumable {
48
        consumer := &asynqConsumer{appName: appName, n: name, c: conf}
49
50
        var rdsCli rdsDrv.UniversalClient
51
        switch conf.InstanceType {
52
        case instanceTypeRedis:
53
                rdsCli = redis.Use(ctx, conf.Instance, redis.AppName(appName))
54
        case instanceTypeDB:
55
                fallthrough
56
        default:
57
                panic(errors.Errorf("unknown instance type: %s", conf.InstanceType))
58
        }
59
60
        if consumer.logger == nil && utils.IsStrNotBlank(conf.Logger) {
61
                loggerType := inspect.TypeOf(conf.Logger)
62
                loggerValue := reflect.New(loggerType)
63
                if loggerValue.Type().Implements(customLoggerType) {
64
                        logger := log.Use(conf.LogInstance, log.AppName(appName))
65
                        loggerValue.Interface().(customLogger).Init(logger, appName, name)
66
                }
67
                consumer.logger = loggerValue.Convert(asynqLoggerType).Interface().(asynq.Logger)
68
        }
69
70
        logLevel := asynq.LogLevel(0)
71
        utils.MustSuccess(logLevel.Set(conf.LogLevel))
72
73
        consumer.ServeMux = asynq.NewServeMux()
74
        asynqCfg := asynq.Config{
75
                Concurrency:    conf.ConsumerConcurrency,
76
                BaseContext:    context.Background,
77
                RetryDelayFunc: asynq.DefaultRetryDelayFunc,
78
                IsFailure:      nil,
79
                Queues:         nil,
80
                StrictPriority: conf.StrictPriority,
81
                ErrorHandler: asynq.ErrorHandlerFunc(func(ctx context.Context, task *asynq.Task, err error) {
82
                        taskName := "unknown"
83
                        if task != nil {
84
                                taskName = consumer.unformatTaskName(task.Type())
85
                        }
86
                        consumer.info(ctx, "handle task %s message error %s", taskName, err)
87
                }),
88
                Logger:                   consumer.logger,
89
                LogLevel:                 logLevel,
90
                ShutdownTimeout:          8 * time.Second,
91
                HealthCheckFunc:          func(err error) { consumer.warn(ctx, "health check check failed: %s", err) },
92
                HealthCheckInterval:      15 * time.Second,
93
                DelayedTaskCheckInterval: 5 * time.Second,
94
                GroupGracePeriod:         1 * time.Minute,
95
                GroupMaxDelay:            0,
96
                GroupMaxSize:             0,
97
                GroupAggregator:          nil,
98
                DisableRedisConnClose:    true,
99
        }
100
        if len(conf.Queues) > 0 {
101
                asynqCfg.Queues = make(map[string]int, len(conf.Queues))
102
                for _, queue := range conf.Queues {
103
                        if _, ok := asynqCfg.Queues[queue.Name]; ok {
104
                                panic(ErrDuplicatedQueueName)
105
                        }
106
                        if utils.IsStrBlank(queue.Name) {
107
                                queue.Name = defaultQueue(appName)
108
                        }
109
                        asynqCfg.Queues[queue.Name] = queue.Level
110
                }
111
        } else {
112
                asynqCfg.Queues = map[string]int{defaultQueue(appName): 3}
113
        }
114
115
        consumer.consumer = asynq.NewServer(&asynqRedisConnOpt{UniversalClient: rdsCli}, asynqCfg)
116
        return consumer
117
}
func asynqProducer.Go
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

300
func (a *asynqProducer) Go(fn any, opts ...utils.OptionExtender) (err error) {
301
        var data any
302
        opt := utils.ApplyOptions[produceOption](opts...)
303
        if len(opt.args) > 0 {
304
                argType, embed := wrapParams(fn)
305
                data = setParams(argType, embed, opt.args...)
306
        }
307
308
        // get task name by func name
309
        funcName := formatTaskName(a.appName, utils.GetFuncName(fn))
310
        callbackMapLock.RLock()
311
        if mappingName, ok := funcNameToTaskName[a.appName][funcName]; ok {
312
                funcName = mappingName
313
        }
314
        callbackMapLock.RUnlock()
315
316
        ctx := context.Background()
317
        task, err := a.newTask(ctx, funcName, data)
318
        if err != nil {
319
                return
320
        }
321
322
        _, err = a.Client.EnqueueContext(ctx, task, a.parseOption(opt)...)
323
        if err != nil {
324
                return
325
        }
326
        return
327
}
func asynqConsumer.info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/log.go:

24
func (a *asynqConsumer) info(ctx context.Context, msg string, args ...any) {
25
        msg = a.format(msg)
26
        if a.logger == nil {
27
                log.Printf(msg, args...)
28
        } else {
29
                logArgs := make([]any, 0, len(args)+2)
30
                logArgs = append(logArgs, ctx, msg)
31
                logArgs = append(logArgs, args...)
32
                a.logger.Info(logArgs...)
33
        }
34
}
func asynqConsumer.Handle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

125
func (a *asynqConsumer) Handle(pattern string, fn any, _ ...utils.OptionExtender) {
126
        if !a.c.Consumer {
127
                a.debug(context.Background(), "cannot handle task: consumer is not enabled")
128
                return
129
        }
130
        name := formatTaskName(a.appName, pattern)
131
        funcName := formatTaskName(a.appName, utils.GetFuncName(fn))
132
133
        callbackMapLock.Lock()
134
        defer callbackMapLock.Unlock()
135
        if callbackMap[a.appName] == nil {
136
                callbackMap[a.appName] = make(map[string]any)
137
        }
138
        if funcNameToTaskName[a.appName] == nil {
139
                funcNameToTaskName[a.appName] = make(map[string]string)
140
        }
141
        if _, ok := callbackMap[a.appName][name]; ok {
142
                panic(ErrDuplicatedHandlerName)
143
        }
144
        callbackMap[a.appName][name] = fn
145
        callbackMap[a.appName][funcName] = fn
146
        funcNameToTaskName[a.appName][funcName] = name
147
148
        typ, embed := wrapParams(fn)
149
        a.ServeMux.Handle(name, a.adaptAsynqHandlerFunc(fn, typ, embed))
150
        if name != funcName {
151
                a.ServeMux.Handle(funcName, a.adaptAsynqHandlerFunc(fn, typ, embed))
152
        }
153
}
func asynqConsumer.Start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

190
func (a *asynqConsumer) Start() (err error) {
191
        if !a.c.Consumer {
192
                return ErrConsumerDisabled
193
        }
194
195
        defer a.info(context.Background(), "consumer started")
196
197
        a.ServeMux.Use(a.gatewayMiddleware)
198
        a.ServeMux.Use(a.mws...)
199
200
        return a.consumer.Start(a.ServeMux)
201
}
func asynqProducer.Goc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

329
func (a *asynqProducer) Goc(ctx context.Context, fn any, opts ...utils.OptionExtender) (err error) {
330
        var data any
331
        opt := utils.ApplyOptions[produceOption](opts...)
332
        if len(opt.args) > 0 {
333
                argType, embed := wrapParams(fn)
334
                data = setParams(argType, embed, opt.args...)
335
        }
336
337
        // get task name by func name
338
        funcName := formatTaskName(a.appName, utils.GetFuncName(fn))
339
        callbackMapLock.RLock()
340
        if mappingName, ok := funcNameToTaskName[a.appName][funcName]; ok {
341
                funcName = mappingName
342
        }
343
        callbackMapLock.RUnlock()
344
345
        task, err := a.newTask(ctx, funcName, data)
346
        if err != nil {
347
                return
348
        }
349
350
        _, err = a.Client.EnqueueContext(ctx, task, a.parseOption(opt)...)
351
        if err != nil {
352
                return
353
        }
354
        return
355
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

58
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
59
        var (
60
                producer Producable
61
                consumer Consumable
62
        )
63
        switch conf.Type {
64
        case asyncTypeAsynq:
65
                if conf.Producer {
66
                        producer = newAsynqProducer(ctx, opt.AppName, name, conf)
67
                }
68
                if conf.Consumer {
69
                        consumer = newAsynqConsumer(ctx, opt.AppName, name, conf)
70
                }
71
        case asyncTypeMysql:
72
                fallthrough
73
        default:
74
                panic(ErrUnsupportedSchedulerType)
75
        }
76
77
        locker.Lock()
78
        defer locker.Unlock()
79
        if consumer != nil {
80
                if consumers == nil {
81
                        consumers = make(map[string]map[string]Consumable)
82
                }
83
                if consumers[opt.AppName] == nil {
84
                        consumers[opt.AppName] = make(map[string]Consumable)
85
                }
86
                if _, ok := consumers[name]; ok {
87
                        panic(ErrDuplicatedInstanceName)
88
                }
89
                consumers[opt.AppName][name] = consumer
90
91
                // ioc
92
                if opt.DI != nil {
93
                        opt.DI.MustProvide(
94
                                func() Consumable { return C(name, AppName(opt.AppName)) },
95
                                di.Name(name),
96
                        )
97
                }
98
        }
99
100
        if producer != nil {
101
                if producers == nil {
102
                        producers = make(map[string]map[string]Producable)
103
                }
104
                if producers[opt.AppName] == nil {
105
                        producers[opt.AppName] = make(map[string]Producable)
106
                }
107
                if _, ok := producers[name]; ok {
108
                        panic(ErrDuplicatedInstanceName)
109
                }
110
                producers[opt.AppName][name] = producer
111
112
                // ioc
113
                if opt.DI != nil {
114
                        opt.DI.MustProvide(
115
                                func() Producable { return P(name) },
116
                                di.Name(name),
117
                        )
118
                }
119
        }
120
}
func P
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

148
func P(name string, opts ...utils.OptionExtender) Producable {
149
        opt := utils.ApplyOptions[useOption](opts...)
150
151
        locker.RLock()
152
        defer locker.RUnlock()
153
        producers, ok := producers[opt.appName]
154
        if !ok {
155
                panic(errors.Errorf("async producer instance not found for app: %s", opt.appName))
156
        }
157
        producer, ok := producers[name]
158
        if !ok {
159
                panic(errors.Errorf("async producer instance not found for name: %s", name))
160
        }
161
        return producer
162
}
func C
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

132
func C(name string, opts ...utils.OptionExtender) Consumable {
133
        opt := utils.ApplyOptions[useOption](opts...)
134
135
        locker.RLock()
136
        defer locker.RUnlock()
137
        consumers, ok := consumers[opt.appName]
138
        if !ok {
139
                panic(errors.Errorf("async consumer instance not found for app: %s", opt.appName))
140
        }
141
        consumer, ok := consumers[name]
142
        if !ok {
143
                panic(errors.Errorf("async consumer instance not found for name: %s", name))
144
        }
145
        return consumer
146
}
func @230:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

230
func(ctx context.Context, task *asynq.Task) (err error) {
231
                ctx, data, _, err := pd.Unseal(task.Payload(), pd.Type(typ))
232
                if err != nil {
233
                        return
234
                }
235
                params := unwrapParams(typ, embed, data)
236
                return fn(append([]any{ctx}, params...)...)
237
        }
func asynqProducer.newTask
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

404
func (a *asynqProducer) newTask(ctx context.Context, taskName string, data any) (task *asynq.Task, err error) {
405
        payload, err := pd.Seal(data, pd.Context(ctx), pd.Serialize(a.serializeType), pd.Compress(a.compressType))
406
        if err != nil {
407
                return
408
        }
409
410
        task = asynq.NewTask(taskName, payload)
411
        return
412
}
func asynqProducer.Send
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

357
func (a *asynqProducer) Send(ctx context.Context, taskName string, data any, opts ...utils.OptionExtender) (err error) {
358
        opt := utils.ApplyOptions[produceOption](opts...)
359
        task, err := a.newTask(ctx, formatTaskName(a.appName, taskName), data)
360
        if err != nil {
361
                return
362
        }
363
364
        _, err = a.Client.EnqueueContext(ctx, task, a.parseOption(opt)...)
365
        if err != nil {
366
                return
367
        }
368
        return
369
}
func asynqConsumer.HandleFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

155
func (a *asynqConsumer) HandleFunc(fn any, _ ...utils.OptionExtender) {
156
        if !a.c.Consumer {
157
                a.debug(context.Background(), "cannot handle task: consumer is not enabled")
158
                return
159
        }
160
        funcName := formatTaskName(a.appName, utils.GetFuncName(fn))
161
162
        callbackMapLock.Lock()
163
        defer callbackMapLock.Unlock()
164
        if callbackMap[a.appName] == nil {
165
                callbackMap[a.appName] = make(map[string]any)
166
        }
167
        if funcNameToTaskName[a.appName] == nil {
168
                funcNameToTaskName[a.appName] = make(map[string]string)
169
        }
170
        if _, ok := callbackMap[funcName]; ok {
171
                panic(ErrDuplicatedHandlerName)
172
        }
173
        callbackMap[a.appName][funcName] = fn
174
175
        typ, embed := wrapParams(fn)
176
        a.ServeMux.Handle(funcName, a.adaptAsynqHandlerFunc(fn, typ, embed))
177
}
func setParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/utils.go:

54
func setParams(typ reflect.Type, embed bool, params ...any) (arg any) {
55
        if typ == nil {
56
                return
57
        }
58
59
        argValPtr := reflect.New(typ)
60
        argVal := argValPtr.Elem()
61
        if !embed {
62
                if len(params) > 0 {
63
                        argVal.Set(reflect.ValueOf(params[0]))
64
                }
65
                return argValPtr.Interface()
66
        }
67
68
        for i := 0; i < len(params); i++ {
69
                ft := argVal.Field(i)
70
                ft.Set(reflect.ValueOf(params[i]).Convert(ft.Type()))
71
        }
72
        return argValPtr.Interface()
73
}
func newAsynqProducer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

274
func newAsynqProducer(ctx context.Context, appName, name string, conf *Conf) Producable {
275
        var rdsCli rdsDrv.UniversalClient
276
        switch conf.InstanceType {
277
        case instanceTypeRedis:
278
                rdsCli = redis.Use(ctx, conf.Instance, redis.AppName(appName))
279
        case instanceTypeDB:
280
                fallthrough
281
        default:
282
                panic(errors.Errorf("unknown instance type: %s", conf.InstanceType))
283
        }
284
285
        producer := &asynqProducer{
286
                appName:       appName,
287
                n:             name,
288
                c:             conf,
289
                Client:        asynq.NewClient(&asynqRedisConnOpt{UniversalClient: rdsCli}),
290
                compressType:  compress.ParseAlgorithm(conf.MessageCompressType),
291
                serializeType: serialize.ParseAlgorithm(conf.MessageSerializeType),
292
        }
293
        // default serialize type
294
        if !producer.serializeType.IsValid() {
295
                producer.serializeType = serialize.AlgorithmGob
296
        }
297
        return producer
298
}
func asynqProducer.parseOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

371
func (a *asynqProducer) parseOption(src *produceOption) (dst []asynq.Option) {
372
        if utils.IsStrNotBlank(src.id) {
373
                dst = append(dst, asynq.TaskID(src.id))
374
        }
375
        if utils.IsStrNotBlank(src.queue) {
376
                dst = append(dst, asynq.Queue(src.queue))
377
        } else if len(a.c.Queues) == 1 {
378
                dst = append(dst, asynq.Queue(a.c.Queues[0].Name))
379
        } else {
380
                dst = append(dst, asynq.Queue(defaultQueue(a.appName)))
381
        }
382
        if src.maxRetry > 0 {
383
                dst = append(dst, asynq.MaxRetry(src.maxRetry))
384
        }
385
        if !src.deadline.IsZero() {
386
                dst = append(dst, asynq.Deadline(src.deadline))
387
        }
388
        if src.timeout > 0 {
389
                dst = append(dst, asynq.Timeout(src.timeout))
390
        }
391
        if src.delayDuration > 0 {
392
                dst = append(dst, asynq.ProcessIn(src.timeout))
393
        }
394
        if !src.delayTime.IsZero() {
395
                dst = append(dst, asynq.ProcessAt(src.delayTime))
396
        }
397
        if src.retentionDuration > 0 {
398
                dst = append(dst, asynq.Retention(src.retentionDuration))
399
        }
400
401
        return
402
}
func asynqConsumer.debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/log.go:

12
func (a *asynqConsumer) debug(ctx context.Context, msg string, args ...any) {
13
        msg = a.format(msg)
14
        if a.logger == nil {
15
                log.Printf(msg, args...)
16
        } else {
17
                logArgs := make([]any, 0, len(args)+2)
18
                logArgs = append(logArgs, ctx, msg)
19
                logArgs = append(logArgs, args...)
20
                a.logger.Debug(logArgs...)
21
        }
22
}
func asynqConsumer.warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/log.go:

36
func (a *asynqConsumer) warn(ctx context.Context, msg string, args ...any) {
37
        msg = a.format(msg)
38
        if a.logger == nil {
39
                log.Printf(msg, args...)
40
        } else {
41
                logArgs := make([]any, 0, len(args)+2)
42
                logArgs = append(logArgs, ctx, msg)
43
                logArgs = append(logArgs, args...)
44
                a.logger.Warn(logArgs...)
45
        }
46
}
func asynqConsumer.Serve
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

179
func (a *asynqConsumer) Serve() (err error) {
180
        if !a.c.Consumer {
181
                return ErrConsumerDisabled
182
        }
183
        defer a.info(context.Background(), "consumer started")
184
185
        a.ServeMux.Use(a.gatewayMiddleware)
186
        a.ServeMux.Use(a.mws...)
187
        return a.consumer.Run(a.ServeMux)
188
}
func @81:40
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

81
func(ctx context.Context, task *asynq.Task, err error) {
82
                        taskName := "unknown"
83
                        if task != nil {
84
                                taskName = consumer.unformatTaskName(task.Type())
85
                        }
86
                        consumer.info(ctx, "handle task %s message error %s", taskName, err)
87
                }
func asynqConsumer.Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

119
func (a *asynqConsumer) Use(mws ...routerMiddleware) {
120
        for _, mw := range mws {
121
                a.mws = append(a.mws, a.adaptMiddleware(mw))
122
        }
123
}
func @220:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

220
func(asynqNext asynq.Handler) asynq.Handler {
221
                next := mw(a.adaptRouterHandlerFunc(asynqNext))
222
                return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
223
                        return next(ctx, a.newTask(t))
224
                })
225
        }
func asynqConsumer.adaptMiddleware
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

219
func (a *asynqConsumer) adaptMiddleware(mw routerMiddleware) asynq.MiddlewareFunc {
220
        return func(asynqNext asynq.Handler) asynq.Handler {
221
                next := mw(a.adaptRouterHandlerFunc(asynqNext))
222
                return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
223
                        return next(ctx, a.newTask(t))
224
                })
225
        }
226
}
func @222:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

222
func(ctx context.Context, t *asynq.Task) error {
223
                        return next(ctx, a.newTask(t))
224
                }
func task.ID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

90
func (t *task) ID() string {
91
        return t.id
92
}
func task.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

94
func (t *task) Name() string {
95
        return t.name
96
}
func task.Payload
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

98
func (t *task) Payload() []byte {
99
        return t.payload
100
}
func task.RawMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

102
func (t *task) RawMessage() any {
103
        return t.rawMessage
104
}
func TaskID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

118
func TaskID(id string) utils.OptionFunc[produceOption] {
119
        return func(o *produceOption) { o.id = id }
120
}
func @119:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

119
func(o *produceOption) { o.id = id }
func @115:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

115
func() Producable { return P(name) }
func asynqConsumer.adaptRouterHandlerFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

240
func (a *asynqConsumer) adaptRouterHandlerFunc(h asynq.Handler) routerMiddlewareFunc {
241
        return func(ctx context.Context, raw Task) (err error) {
242
                return h.ProcessTask(ctx, a.newAsynqTask(raw))
243
        }
244
}
func Delay
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

136
func Delay(d time.Duration) utils.OptionFunc[produceOption] {
137
        return func(o *produceOption) { o.delayDuration = d }
138
}
func @241:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

241
func(ctx context.Context, raw Task) (err error) {
242
                return h.ProcessTask(ctx, a.newAsynqTask(raw))
243
        }
func MaxRetry
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

127
func MaxRetry(n int) utils.OptionFunc[produceOption] {
128
        return func(o *produceOption) { o.maxRetry = n }
129
}
func @128:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

128
func(o *produceOption) { o.maxRetry = n }
func Deadline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

130
func Deadline(t time.Time) utils.OptionFunc[produceOption] {
131
        return func(o *produceOption) { o.deadline = t }
132
}
func @131:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

131
func(o *produceOption) { o.deadline = t }
func Timeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

133
func Timeout(d time.Duration) utils.OptionFunc[produceOption] {
134
        return func(o *produceOption) { o.timeout = d }
135
}
func @134:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

134
func(o *produceOption) { o.timeout = d }
func asynqConsumer.newTask
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

250
func (a *asynqConsumer) newTask(raw *asynq.Task) (t Task) {
251
        return &task{
252
                id:         raw.Type(),
253
                name:       raw.Type(),
254
                payload:    raw.Payload(),
255
                rawMessage: raw,
256
        }
257
}
func @137:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

137
func(o *produceOption) { o.delayDuration = d }
func DelayAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

139
func DelayAt(t time.Time) utils.OptionFunc[produceOption] {
140
        return func(o *produceOption) { o.delayTime = t }
141
}
func @140:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

140
func(o *produceOption) { o.delayTime = t }
func Retention
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

142
func Retention(d time.Duration) utils.OptionFunc[produceOption] {
143
        return func(o *produceOption) { o.retentionDuration = d }
144
}
func @143:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/types.go:

143
func(o *produceOption) { o.retentionDuration = d }
func @91:29
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

91
func(err error) { consumer.warn(ctx, "health check check failed: %s", err) }
func asynqConsumer.newAsynqTask
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/asynq.go:

259
func (a *asynqConsumer) newAsynqTask(raw Task) (t *asynq.Task) {
260
        return raw.RawMessage().(*asynq.Task)
261
}
func @94:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/async/construct.go:

94
func() Consumable { return C(name, AppName(opt.AppName)) }
Package Overview: github.com/wfusion/gofusion/cache 76.9%

Please select a function to see what's left for testing.

.parseCallbackOption(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 13/13
.convValToInner(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 3/3
Construct(...) github.com/wfusion/gofusion/cache/construct.go 100.0% 3/3
@192:8(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 2/2
.unseal(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 2/2
.convInnerToKey(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 2/2
.convKeysToInner(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/cache/construct.go 100.0% 1/1
newRedis(...) github.com/wfusion/gofusion/cache/redis.go 100.0% 1/1
Expired(...) github.com/wfusion/gofusion/cache/types.go 100.0% 1/1
@237:34(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
.convKeyToInner(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
.convInnerToKeys(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
@247:39(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
@39:9(...) github.com/wfusion/gofusion/cache/types.go 100.0% 1/1
KeyExpired(...) github.com/wfusion/gofusion/cache/types.go 100.0% 1/1
@52:9(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
.seal(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/cache/cache.go 100.0% 1/1
@45:9(...) github.com/wfusion/gofusion/cache/types.go 100.0% 1/1
gCache.get(...) github.com/wfusion/gofusion/cache/local.go 90.9% 10/11
.Get(...) github.com/wfusion/gofusion/cache/cache.go 88.5% 23/26
.convInnerToVal(...) github.com/wfusion/gofusion/cache/cache.go 86.7% 13/15
.Del(...) github.com/wfusion/gofusion/cache/cache.go 85.7% 6/7
.Set(...) github.com/wfusion/gofusion/cache/cache.go 85.7% 6/7
.Clear(...) github.com/wfusion/gofusion/cache/cache.go 85.7% 6/7
.getConfig(...) github.com/wfusion/gofusion/cache/cache.go 84.6% 22/26
rds.set(...) github.com/wfusion/gofusion/cache/redis.go 76.9% 10/13
rds.get(...) github.com/wfusion/gofusion/cache/redis.go 69.2% 9/13
New(...) github.com/wfusion/gofusion/cache/cache.go 69.2% 9/13
rds.del(...) github.com/wfusion/gofusion/cache/redis.go 66.7% 14/21
gCache.del(...) github.com/wfusion/gofusion/cache/local.go 66.7% 6/9
.convInnerToMap(...) github.com/wfusion/gofusion/cache/cache.go 63.6% 7/11
gCache.set(...) github.com/wfusion/gofusion/cache/local.go 63.6% 7/11
.convMapToInner(...) github.com/wfusion/gofusion/cache/cache.go 63.6% 7/11
.GetAll(...) github.com/wfusion/gofusion/cache/cache.go 63.0% 17/27
addInstance(...) github.com/wfusion/gofusion/cache/construct.go 54.5% 6/11
newGCache(...) github.com/wfusion/gofusion/cache/local.go 50.0% 4/8
.cloneVal(...) github.com/wfusion/gofusion/cache/cache.go 50.0% 2/4
@21:9(...) github.com/wfusion/gofusion/cache/construct.go 100.0% 0/0
func .parseCallbackOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

325
func (c *cache[K, T, TS]) parseCallbackOption(kvs map[K]T, conf *parsedConf[K, T], opts ...utils.OptionExtender) (
326
        exp map[string]time.Duration) {
327
        opt := utils.ApplyOptions[option[K]](opts...)
328
        exp = make(map[string]time.Duration, len(kvs))
329
330
        // opt.keyExpired > opt.expired > conf.expired
331
        if conf.expired > 0 {
332
                for k := range kvs {
333
                        innerKey := c.convKeyToInner(k, conf.version)
334
                        exp[innerKey] = conf.expired
335
                }
336
        }
337
338
        if opt.expired > 0 {
339
                for k := range kvs {
340
                        innerKey := c.convKeyToInner(k, conf.version)
341
                        exp[innerKey] = conf.expired
342
                }
343
        }
344
345
        for k, e := range opt.keyExpired {
346
                exp[c.convKeyToInner(k, conf.version)] = e
347
        }
348
349
        return
350
}
func .convValToInner
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

276
func (c *cache[K, T, TS]) convValToInner(src T, conf *parsedConf[K, T]) (dst any, err error) {
277
        if !conf.serializeType.IsValid() && !conf.compressType.IsValid() {
278
                return c.cloneVal(src), nil
279
        }
280
281
        return c.seal(src, conf)
282
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/construct.go:

16
func Construct(ctx context.Context, confs map[string]*Conf, _ ...utils.OptionExtender) func() {
17
        for _, conf := range confs {
18
                addInstance(ctx, conf)
19
        }
20
21
        return func() {
22
23
        }
24
}
func @192:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

192
func() {
193
                innerKeys := utils.MapKeys(innerVals)
194
                c.visited.Insert(innerKeys...)
195
        }
func .unseal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

356
func (c *cache[K, T, TS]) unseal(src []byte) (dst T, ok bool, err error) {
357
        _, dst, ok, err = pd.UnsealT[T](src)
358
        return
359
}
func .convInnerToKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

252
func (c *cache[K, T, TS]) convInnerToKey(inner string, ver int) (k K) {
253
        key := strings.TrimPrefix(inner, fmt.Sprintf("%s:%v:", c.prefix, ver))
254
        return utils.SortableToGeneric[string, K](key)
255
}
func .convKeysToInner
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

236
func (c *cache[K, T, TS]) convKeysToInner(keys []K, version int) (inner []string) {
237
        return utils.SliceMapping(keys, func(k K) string {
238
                return c.convKeyToInner(k, version)
239
        })
240
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/construct.go:

51
func init() {
52
        config.AddComponent(config.ComponentCache, Construct)
53
}
func newRedis
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/redis.go:

23
func newRedis(appName, name string, log log.Loggable) provider {
24
        return &rds{
25
                appName:  appName,
26
                name:     name,
27
                log:      log,
28
                instance: redis.Use(context.Background(), name, redis.AppName(appName)),
29
        }
30
}
func Expired
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/types.go:

38
func Expired[K constraint.Sortable](expired time.Duration) utils.OptionFunc[option[K]] {
39
        return func(o *option[K]) {
40
                o.expired = expired
41
        }
42
}
func @237:34
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

237
func(k K) string {
238
                return c.convKeyToInner(k, version)
239
        }
func .convKeyToInner
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

242
func (c *cache[K, T, TS]) convKeyToInner(k K, ver int) (inner string) {
243
        return fmt.Sprintf("%s:%v:%s", c.prefix, ver, cast.ToString(k))
244
}
func .convInnerToKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

246
func (c *cache[K, T, TS]) convInnerToKeys(innerKeys []string, ver int) (keys []K) {
247
        return utils.SliceMapping(innerKeys, func(inner string) K {
248
                return c.convInnerToKey(inner, ver)
249
        })
250
}
func @247:39
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

247
func(inner string) K {
248
                return c.convInnerToKey(inner, ver)
249
        }
func @39:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/types.go:

39
func(o *option[K]) {
40
                o.expired = expired
41
        }
func KeyExpired
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/types.go:

44
func KeyExpired[K constraint.Sortable](keyExpired map[K]time.Duration) utils.OptionFunc[option[K]] {
45
        return func(o *option[K]) {
46
                o.keyExpired = keyExpired
47
        }
48
}
func @52:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

52
func(o *initOption) {
53
                o.appName = name
54
        }
func .seal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

352
func (c *cache[K, T, TS]) seal(src T, conf *parsedConf[K, T]) (dst []byte, err error) {
353
        return pd.Seal(src, pd.Serialize(conf.serializeType), pd.Compress(conf.compressType))
354
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

51
func AppName(name string) utils.OptionFunc[initOption] {
52
        return func(o *initOption) {
53
                o.appName = name
54
        }
55
}
func @45:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/types.go:

45
func(o *option[K]) {
46
                o.keyExpired = keyExpired
47
        }
func gCache.get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/local.go:

41
func (g *gCache) get(ctx context.Context, keys ...string) (cached map[string]any, missed []string) {
42
        cached = make(map[string]any, len(keys))
43
        missed = make([]string, 0, len(keys))
44
        for _, k := range keys {
45
                v, err := g.instance.Get(k)
46
                if err != nil {
47
                        missed = append(missed, k)
48
                        if !errors.Is(err, gcache.KeyNotFoundError) && g.log != nil {
49
                                g.log.Info(ctx, "%v [Gofusion] %s call gcache get failed "+
50
                                        "when get cache from gcache [err[%s] key[%s]]", syscall.Getpid(), config.ComponentCache, err, k)
51
                        }
52
                        continue
53
                }
54
                cached[k] = v
55
        }
56
        return
57
}
func .Get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

96
func (c *cache[K, T, TS]) Get(ctx context.Context, keys []K, cb callback[K, T]) (ts TS) {
97
        conf := c.getConfig()
98
        innerKeys := c.convKeysToInner(keys, conf.version)
99
        cached, missed := c.provider.get(ctx, innerKeys...)
100
        kvs, _ := c.convInnerToMap(ctx, cached, conf)
101
        defer c.visited.Insert(innerKeys...)
102
103
        if cb == nil {
104
                cb = conf.callback
105
        }
106
        if len(missed) > 0 && cb != nil {
107
                keys := c.convInnerToKeys(missed, conf.version)
108
                if conf.log != nil {
109
                        conf.log.Debug(ctx, "%v [Gofusion] %s call callback function because we do not hit the cache "+
110
                                "when get [keys%+v]", syscall.Getpid(), config.ComponentCache, keys)
111
                }
112
113
                callbackKVs, opts := cb(ctx, keys)
114
                kvs = utils.MapMerge(kvs, callbackKVs)
115
                innerVals, _ := c.convMapToInner(ctx, callbackKVs, conf)
116
                _ = c.provider.set(ctx, innerVals, c.parseCallbackOption(kvs, conf, opts...))
117
                // innerFailureKeys = append(innerFailureKeys, convInnerFailureKeys...)
118
        }
119
120
        // order by param -> keys
121
        ts = make(TS, 0, len(kvs))
122
        missedKeys := make([]K, 0, len(keys))
123
        for _, k := range keys {
124
                v, ok := kvs[k]
125
                if !ok {
126
                        missedKeys = append(missedKeys, k)
127
                        continue
128
                }
129
130
                ts = append(ts, v)
131
        }
132
        if len(missedKeys) > 0 && conf.log != nil {
133
                conf.log.Info(ctx, "%v [Gofusion] %s we still get missing keys after callback when cache get [keys%v]",
134
                        syscall.Getpid(), config.ComponentCache, missedKeys)
135
        }
136
137
        return
138
}
func .convInnerToVal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

303
func (c *cache[K, T, TS]) convInnerToVal(src any) (dst T, err error) {
304
        srcBytes, ok1 := src.([]byte)
305
        srcString, ok2 := src.(string)
306
        if !ok1 && !ok2 {
307
                return c.cloneVal(src.(T)), nil
308
        }
309
        if ok2 {
310
                buffer, cb := utils.BytesBufferPool.Get(nil)
311
                defer cb()
312
                buffer.WriteString(srcString)
313
                srcBytes = buffer.Bytes()
314
        }
315
        dst, ok, err := c.unseal(srcBytes)
316
        if err != nil {
317
                return
318
        }
319
        if !ok {
320
                return c.cloneVal(src.(T)), nil
321
        }
322
        return
323
}
func .Del
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

210
func (c *cache[K, T, TS]) Del(ctx context.Context, keys ...K) (failure []K) {
211
        conf := c.getConfig()
212
        innerKeys := c.convKeysToInner(keys, conf.version)
213
        innerFailureKeys := c.provider.del(ctx, innerKeys...)
214
        defer c.visited.Remove(innerKeys...)
215
216
        if failure = c.convInnerToKeys(innerFailureKeys, conf.version); len(failure) > 0 && conf.log != nil {
217
                conf.log.Info(ctx, "%v [Gofusion] %s del some kvs failed when del [keys%+v]",
218
                        syscall.Getpid(), config.ComponentCache, failure)
219
        }
220
        return
221
}
func .Set
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

189
func (c *cache[K, T, TS]) Set(ctx context.Context, kvs map[K]T, opts ...utils.OptionExtender) (failure []K) {
190
        conf := c.getConfig()
191
        innerVals, innerFailureKeys := c.convMapToInner(ctx, kvs, conf)
192
        defer func() {
193
                innerKeys := utils.MapKeys(innerVals)
194
                c.visited.Insert(innerKeys...)
195
        }()
196
197
        innerFailureKeys = append(
198
                innerFailureKeys,
199
                c.provider.set(ctx, innerVals, c.parseCallbackOption(kvs, conf, opts...))...,
200
        )
201
202
        if failure = c.convInnerToKeys(innerFailureKeys, conf.version); len(failure) > 0 && conf.log != nil {
203
                conf.log.Info(ctx, "%v [Gofusion] %s set some kvs failed when set [keys%+v vals%+v]",
204
                        syscall.Getpid(), config.ComponentCache, failure, utils.MapValuesByKeys(kvs, failure))
205
        }
206
207
        return
208
}
func .Clear
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

223
func (c *cache[K, T, TS]) Clear(ctx context.Context) (failureKeys []K) {
224
        conf := c.getConfig()
225
        innerKeys := c.visited.Items()
226
        innerFailureKeys := c.provider.del(ctx, innerKeys...)
227
        defer c.visited.Remove(innerKeys...)
228
229
        if failureKeys = c.convInnerToKeys(innerFailureKeys, conf.version); len(failureKeys) > 0 && conf.log != nil {
230
                conf.log.Info(ctx, "%v [Gofusion] %s del some kvs failed when clear [keys%+v]",
231
                        syscall.Getpid(), config.ComponentCache, failureKeys)
232
        }
233
        return
234
}
func .getConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

369
func (c *cache[K, T, TS]) getConfig() (conf *parsedConf[K, T]) {
370
        var cfgs map[string]*Conf
371
        _ = config.Use(c.appName).LoadComponentConfig(config.ComponentCache, &cfgs)
372
        if len(cfgs) == 0 {
373
                panic(ErrCacheNotFound)
374
        }
375
376
        cfg, ok := cfgs[c.name]
377
        if !ok {
378
                panic(ErrCacheNotFound)
379
        }
380
381
        conf = &parsedConf[K, T]{
382
                size:           cfg.Size,
383
                localEvictType: cfg.LocalEvictType,
384
                cacheType:      cfg.CacheType,
385
                remoteType:     cfg.RemoteType,
386
                remoteInstance: cfg.RemoteInstance,
387
                version:        cfg.Version,
388
        }
389
        if utils.IsStrNotBlank(cfg.Expired) {
390
                conf.expired = utils.Must(time.ParseDuration(cfg.Expired))
391
        }
392
        if utils.IsStrNotBlank(cfg.LogInstance) {
393
                conf.log = log.Use(cfg.LogInstance, log.AppName(c.appName))
394
        }
395
396
        if utils.IsStrNotBlank(cfg.SerializeType) {
397
                conf.serializeType = serialize.ParseAlgorithm(cfg.SerializeType)
398
        }
399
400
        if utils.IsStrNotBlank(cfg.Compress) {
401
                conf.compressType = compress.ParseAlgorithm(cfg.Compress)
402
                if !conf.compressType.IsValid() {
403
                        panic(UnknownCompress)
404
                }
405
        }
406
        // default serialize type when need compress
407
        if conf.compressType.IsValid() && !conf.serializeType.IsValid() {
408
                conf.serializeType = serialize.AlgorithmGob
409
        }
410
411
        if utils.IsStrNotBlank(cfg.Callback) {
412
                callbackFn := inspect.FuncOf(cfg.Callback)
413
                if callbackFn == nil {
414
                        panic(errors.Errorf("not found callback function: %s", cfg.Callback))
415
                }
416
                conf.callback = *(*func(ctx context.Context, missed []K) (rs map[K]T, opts []utils.OptionExtender))(callbackFn)
417
        }
418
419
        return
420
}
func rds.set
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/redis.go:

56
func (r *rds) set(ctx context.Context, kvs map[string]any, expired map[string]time.Duration) (failure []string) {
57
        failure = make([]string, 0, len(kvs))
58
        pipe := r.instance.Pipeline()
59
        keys := make([]string, 0, len(kvs))
60
        for k, v := range kvs {
61
                keys = append(keys, k)
62
                pipe.Set(ctx, k, v, expired[k])
63
        }
64
65
        cmds := utils.Must(pipe.Exec(ctx))
66
        for i := 0; i < len(keys); i++ {
67
                if err := cmds[i].Err(); err != nil {
68
                        failure = append(failure, keys[i])
69
                        if r.log != nil {
70
                                r.log.Info(ctx, "%v [Gofusion] %s call redis set failed when set cache into redis "+
71
                                        "[err[%s] redis[%s] key[%s]]", syscall.Getpid(), config.ComponentCache, err, r.name, keys[i])
72
                        }
73
                }
74
        }
75
        return
76
}
func rds.get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/redis.go:

32
func (r *rds) get(ctx context.Context, keys ...string) (cached map[string]any, missed []string) {
33
        cached = make(map[string]any, len(keys))
34
        missed = make([]string, 0, len(keys))
35
36
        rs, err := r.instance.MGet(ctx, keys...).Result()
37
        if err != nil {
38
                missed = keys
39
                if r.log != nil {
40
                        r.log.Info(ctx, "%v [Gofusion] %s call redis mget failed when get cache from redis "+
41
                                "[err[%s] redis[%s]]", syscall.Getpid(), config.ComponentCache, err, r.name)
42
                }
43
                return
44
        }
45
        for i := 0; i < len(keys); i++ {
46
                if rs[i] != nil {
47
                        cached[keys[i]] = rs[i]
48
                } else {
49
                        missed = append(missed, keys[i])
50
                }
51
        }
52
53
        return
54
}
func New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

57
func New[K constraint.Sortable, T any, TS ~[]T](name string, opts ...utils.OptionExtender) Cachable[K, T, TS] {
58
        opt := utils.ApplyOptions[initOption](opts...)
59
60
        instance := &cache[K, T, TS]{
61
                name:    name,
62
                appName: opt.appName,
63
                prefix:  fmt.Sprintf("%s:%s", config.Use(opt.appName).AppName(), name),
64
                visited: utils.NewSet[string](),
65
        }
66
67
        conf := instance.getConfig()
68
        switch conf.cacheType {
69
        case cacheTypeLocal:
70
                instance.provider = newGCache(conf.size, conf.localEvictType, conf.log)
71
        case cacheTypeRemote:
72
                if conf.remoteType != remoteTypeRedis {
73
                        panic(UnknownRemoteType)
74
                }
75
                if !conf.serializeType.IsValid() && !conf.compressType.IsValid() {
76
                        panic(UnknownSerializeType)
77
                }
78
                instance.provider = newRedis(opt.appName, conf.remoteInstance, conf.log)
79
        case cacheTypeRemoteLocal:
80
                panic(ErrNotImplement)
81
        default:
82
                panic(UnknownCacheType)
83
        }
84
85
        return instance
86
}
func rds.del
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/redis.go:

78
func (r *rds) del(ctx context.Context, keys ...string) (failure []string) {
79
        affected, err := r.instance.Del(ctx, keys...).Result()
80
        if err != nil && r.log != nil {
81
                r.log.Info(ctx, "%v [Gofusion] %s call redis del failed when delete from cache "+
82
                        "[err[%s] redis[%s] keys%v]", syscall.Getpid(), config.ComponentCache, err, r.name, keys)
83
        }
84
85
        if affected == int64(len(keys)) {
86
                return
87
        }
88
89
        failure = make([]string, 0, len(keys))
90
        pipe := r.instance.Pipeline()
91
        for i := 0; i < len(keys); i++ {
92
                pipe.Exists(ctx, keys[i])
93
        }
94
        cmds, err := pipe.Exec(ctx)
95
        if err != nil && r.log != nil {
96
                r.log.Info(ctx, "%v [Gofusion] %s call redis exists failed when delete from cache "+
97
                        "[err[%s] redis[%s] keys%v]", syscall.Getpid(), config.ComponentCache, err, r.name, keys)
98
                return keys // we cannot know whether ths keys are deleted
99
        }
100
101
        for i := 0; i < len(keys); i++ {
102
                if err := cmds[i].Err(); err != nil {
103
                        failure = append(failure, keys[i]) // we cannot know whether ths key is deleted
104
                        r.log.Info(ctx, "%v [Gofusion] %s call redis exists failed when delete from cache "+
105
                                "[err[%s] redis[%s] key[%s]]", syscall.Getpid(), config.ComponentCache, err, r.name, keys[i])
106
                        continue
107
                }
108
109
                if cmds[i].String() == "1" {
110
                        failure = append(failure, keys[i])
111
                }
112
        }
113
114
        return
115
}
func gCache.del
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/local.go:

80
func (g *gCache) del(ctx context.Context, keys ...string) (failure []string) {
81
        failure = make([]string, 0, len(keys))
82
        for _, k := range keys {
83
                if g.instance.Remove(k) {
84
                        continue
85
                }
86
87
                if _, err := g.instance.Get(k); !errors.Is(err, gcache.KeyNotFoundError) {
88
                        failure = append(failure, k)
89
                        if g.log != nil {
90
                                g.log.Info(ctx, "%v [Gofusion] %s call gcache remove failed "+
91
                                        "when delete cache from gcache [err[%s] key[%s]]", syscall.Getpid(), config.ComponentCache, err, k)
92
                        }
93
                }
94
        }
95
        return
96
}
func .convInnerToMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

284
func (c *cache[K, T, TS]) convInnerToMap(ctx context.Context, inner map[string]any, conf *parsedConf[K, T]) (
285
        kvs map[K]T, innerFailureKeys []string) {
286
        kvs = make(map[K]T, len(inner))
287
        for k, v := range inner {
288
                innerKey := c.convInnerToKey(k, conf.version)
289
                innerVal, err := c.convInnerToVal(v)
290
                if err != nil {
291
                        if conf.log != nil {
292
                                conf.log.Info(ctx, "%v [Gofusion] %s convert inner to value failed [err[%s] key[%+v] val[%+v]]",
293
                                        syscall.Getpid(), config.ComponentCache, err, innerKey, v)
294
                        }
295
                        innerFailureKeys = append(innerFailureKeys, k)
296
                        continue
297
                }
298
                kvs[innerKey] = innerVal
299
        }
300
        return
301
}
func gCache.set
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/local.go:

59
func (g *gCache) set(ctx context.Context, kvs map[string]any, expired map[string]time.Duration) (failure []string) {
60
        failure = make([]string, 0, len(kvs))
61
        for k, v := range kvs {
62
                var err error
63
                if exp, ok := expired[k]; ok {
64
                        err = g.instance.SetWithExpire(k, v, exp)
65
                } else {
66
                        err = g.instance.Set(k, v)
67
                }
68
69
                if err != nil {
70
                        failure = append(failure, k)
71
                        if g.log != nil {
72
                                g.log.Info(ctx, "%v [Gofusion] %s call gcache set/set_with_expire failed "+
73
                                        "when set cache into gcache [err[%s] key[%s]]", syscall.Getpid(), config.ComponentCache, err, k)
74
                        }
75
                }
76
        }
77
        return
78
}
func .convMapToInner
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

257
func (c *cache[K, T, TS]) convMapToInner(ctx context.Context, kvs map[K]T, conf *parsedConf[K, T]) (
258
        inner map[string]any, innerFailureKeys []string) {
259
        inner = make(map[string]any, len(kvs))
260
        for k, v := range kvs {
261
                innerKey := c.convKeyToInner(k, conf.version)
262
                innerVal, err := c.convValToInner(v, conf)
263
                if err != nil {
264
                        if conf.log != nil {
265
                                conf.log.Info(ctx, "%v [Gofusion] %s convert value to inner failed [err[%s] key[%+v] val[%+v]]",
266
                                        syscall.Getpid(), config.ComponentCache, err, k, v)
267
                        }
268
                        innerFailureKeys = append(innerFailureKeys, innerKey)
269
                        continue
270
                }
271
                inner[innerKey] = innerVal
272
        }
273
        return
274
}
func .GetAll
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

140
func (c *cache[K, T, TS]) GetAll(ctx context.Context, cb callback[K, T]) (ts TS) {
141
        conf := c.getConfig()
142
        allInnerKeys := c.visited.Items()
143
        cached, missed := c.provider.get(ctx, allInnerKeys...)
144
        kvs, _ := c.convInnerToMap(ctx, cached, conf)
145
        if len(missed) > 0 && (cb != nil || conf.callback != nil) {
146
                keys := c.convInnerToKeys(missed, conf.version)
147
                if conf.log != nil {
148
                        conf.log.Info(ctx, "%v [Gofusion] %s call callback function because we do not hit the cache "+
149
                                "when get all [keys%+v]", syscall.Getpid(), config.ComponentCache, keys)
150
                }
151
152
                var (
153
                        callbackKVs map[K]T
154
                        opts        []utils.OptionExtender
155
                )
156
                if cb != nil {
157
                        callbackKVs, opts = cb(ctx, keys)
158
                } else {
159
                        callbackKVs, opts = conf.callback(ctx, keys)
160
                }
161
162
                kvs = utils.MapMerge(kvs, callbackKVs)
163
164
                innerVals, _ := c.convMapToInner(ctx, callbackKVs, conf)
165
                c.provider.set(ctx, innerVals, c.parseCallbackOption(kvs, conf, opts...))
166
        }
167
168
        // order by param -> keys
169
        ts = make(TS, 0, len(kvs))
170
        missedKeys := make([]K, 0, len(allInnerKeys))
171
        for _, k := range c.convInnerToKeys(allInnerKeys, conf.version) {
172
                v, ok := kvs[k]
173
                if !ok {
174
                        missedKeys = append(missedKeys, k)
175
                        continue
176
                }
177
178
                ts = append(ts, v)
179
        }
180
        c.visited.Remove(c.convKeysToInner(missedKeys, conf.version)...)
181
        if len(missedKeys) > 0 && conf.log != nil {
182
                conf.log.Warn(ctx, "%v [Gofusion] %s index key value failed when cache get all [keys%v]",
183
                        syscall.Getpid(), config.ComponentCache, missedKeys)
184
        }
185
186
        return
187
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/construct.go:

26
func addInstance(ctx context.Context, conf *Conf) {
27
        switch conf.CacheType {
28
        case cacheTypeLocal:
29
        case cacheTypeRemote:
30
                if conf.RemoteType != remoteTypeRedis {
31
                        panic(UnknownRemoteType)
32
                }
33
34
                parsedSerializeType := serialize.ParseAlgorithm(conf.SerializeType)
35
                parsedCompressType := compress.ParseAlgorithm(conf.Compress)
36
                if !parsedSerializeType.IsValid() && !parsedCompressType.IsValid() {
37
                        panic(UnknownSerializeType)
38
                }
39
        case cacheTypeRemoteLocal:
40
                panic(ErrNotImplement)
41
42
        default:
43
                panic(UnknownCacheType)
44
        }
45
46
        if utils.IsStrNotBlank(conf.Callback) && inspect.FuncOf(conf.Callback) == nil {
47
                panic(errors.Errorf("not found callback function: %s", conf.Callback))
48
        }
49
}
func newGCache
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/local.go:

15
func newGCache(size int, strategy string, log log.Loggable) *gCache {
16
        cacheBuilder := gcache.New(size)
17
        switch strategy {
18
        case gcache.TYPE_ARC:
19
                cacheBuilder = cacheBuilder.ARC()
20
        case gcache.TYPE_LFU:
21
                cacheBuilder = cacheBuilder.LFU()
22
        case gcache.TYPE_LRU:
23
                cacheBuilder = cacheBuilder.LRU()
24
        case gcache.TYPE_SIMPLE:
25
                cacheBuilder = cacheBuilder.Simple()
26
        default:
27
                cacheBuilder = cacheBuilder.ARC()
28
        }
29
30
        return &gCache{
31
                log:      log,
32
                instance: cacheBuilder.Build(),
33
        }
34
}
func .cloneVal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/cache.go:

361
func (c *cache[K, T, TS]) cloneVal(src T) (dst T) {
362
        if cl, ok := any(src).(clone.Clonable[T]); ok {
363
                dst = cl.Clone()
364
                return
365
        }
366
        return clone.Slowly(src)
367
}
func @21:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cache/construct.go:

21
func() {
22
23
        }
Package Overview: github.com/wfusion/gofusion/common/constant 75.0%

Please select a function to see what's left for testing.

DefaultLocation(...) github.com/wfusion/gofusion/common/constant/time_format.go 75.0% 3/4
func DefaultLocation
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/constant/time_format.go:

18
func DefaultLocation() *time.Location {
19
        loc, err := time.LoadLocation(DefaultTimezone)
20
        if err != nil {
21
                panic(err)
22
        }
23
        return loc
24
}
Package Overview: github.com/wfusion/gofusion/common/di 69.0%

Please select a function to see what's left for testing.

_dig.MustProvide(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 2/2
Name(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
@40:9(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
_dig.Clear(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
_dig.Invoke(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
_dig.MustInvoke(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
NewDI(...) github.com/wfusion/gofusion/common/di/dig.go 100.0% 1/1
_dig.Preload(...) github.com/wfusion/gofusion/common/di/dig.go 87.5% 14/16
_dig.Provide(...) github.com/wfusion/gofusion/common/di/dig.go 87.5% 7/8
_dig.addFields(...) github.com/wfusion/gofusion/common/di/dig.go 55.0% 11/20
_dig.MustDecorate(...) github.com/wfusion/gofusion/common/di/dig.go 0.0% 0/2
_dig.Decorate(...) github.com/wfusion/gofusion/common/di/dig.go 0.0% 0/1
_dig.String(...) github.com/wfusion/gofusion/common/di/dig.go 0.0% 0/1
@46:9(...) github.com/wfusion/gofusion/common/di/dig.go 0.0% 0/1
Group(...) github.com/wfusion/gofusion/common/di/dig.go 0.0% 0/1
func _dig.MustProvide
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

66
func (d *_dig) MustProvide(ctor any, opts ...utils.OptionExtender) DI {
67
        utils.MustSuccess(d.Provide(ctor, opts...))
68
        return d
69
}
func Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

39
func Name(name string) utils.OptionFunc[provideOption] {
40
        return func(p *provideOption) {
41
                p.name = name
42
        }
43
}
func @40:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

40
func(p *provideOption) {
41
                p.name = name
42
        }
func _dig.Clear
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

80
func (d *_dig) Clear() {
81
        d.Container = dig.New()
82
}
func _dig.Invoke
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

51
func (d *_dig) Invoke(fn any) error { return d.Container.Invoke(fn) }
func _dig.MustInvoke
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

52
func (d *_dig) MustInvoke(fn any)   { utils.MustSuccess(d.Container.Invoke(fn)) }
func NewDI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

30
func NewDI() DI {
31
        return &_dig{Container: dig.New()}
32
}
func _dig.Preload
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

86
func (d *_dig) Preload() {
87
        fields := make([]reflect.StructField, 0, 1+len(d.fields))
88
        fields = append(fields, reflect.StructField{
89
                Name:      "In",
90
                PkgPath:   "",
91
                Type:      digInType,
92
                Tag:       "",
93
                Offset:    0,
94
                Index:     nil,
95
                Anonymous: true,
96
        })
97
        for i := 0; i < len(d.fields); i++ {
98
                fields = append(fields, reflect.StructField{
99
                        Name:      fmt.Sprintf("Arg%X", i+1),
100
                        PkgPath:   "",
101
                        Type:      d.fields[i].Type,
102
                        Tag:       d.fields[i].Tag,
103
                        Offset:    0,
104
                        Index:     nil,
105
                        Anonymous: false,
106
                })
107
        }
108
        structType := reflect.StructOf(fields)
109
110
        // FIXME: we cannot declare function param type dynamic now
111
        scope := inspect.GetField[*dig.Scope](d.Container, "scope")
112
        containerStoreType := inspect.TypeOf("go.uber.org/dig.containerStore")
113
        containerStoreVal := reflect.ValueOf(scope).Convert(containerStoreType)
114
115
        fakeParam := utils.Must(newParam(structType, scope))
116
        paramType := inspect.TypeOf("go.uber.org/dig.param")
117
        paramVal := reflect.ValueOf(fakeParam).Convert(paramType)
118
        buildFn := paramVal.MethodByName("Build")
119
        returnValList := buildFn.Call([]reflect.Value{containerStoreVal})
120
        if errVal := returnValList[len(returnValList)-1].Interface(); errVal != nil {
121
                if err, ok := errVal.(error); ok && err != nil {
122
                        panic(err)
123
                }
124
        }
125
}
func _dig.Provide
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

53
func (d *_dig) Provide(ctor any, opts ...utils.OptionExtender) (err error) {
54
        opt := utils.ApplyOptions[provideOption](opts...)
55
        digOpts := make([]dig.ProvideOption, 0, 2)
56
        if opt.name != "" {
57
                digOpts = append(digOpts, dig.Name(opt.name))
58
        }
59
        if opt.group != "" {
60
                digOpts = append(digOpts, dig.Group(opt.group))
61
        }
62
63
        defer d.addFields(ctor, opt)
64
        return d.Container.Provide(ctor, digOpts...)
65
}
func _dig.addFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

127
func (d *_dig) addFields(ctor any, opt *provideOption) {
128
        typ := reflect.TypeOf(ctor)
129
        numOfOut := typ.NumOut()
130
        for i := 0; i < numOfOut; i++ {
131
                out := typ.Out(i)
132
                // ignore error and non-interface nor non-struct out param
133
                if out == constant.ErrorType ||
134
                        (out.Kind() != reflect.Interface &&
135
                                (out.Kind() != reflect.Struct && !(out.Kind() == reflect.Ptr && out.Elem().Kind() == reflect.Struct))) {
136
                        continue
137
                }
138
                if !utils.EmbedsType(out, digOutType) {
139
                        var tag reflect.StructTag
140
                        switch {
141
                        case opt.name != "":
142
                                tag = reflect.StructTag(fmt.Sprintf(`name:"%s"`, opt.name))
143
                        case opt.group != "":
144
                                tag = reflect.StructTag(fmt.Sprintf(`group:"%s"`, opt.group))
145
                                out = reflect.SliceOf(out)
146
                        }
147
148
                        d.fields = append(d.fields, reflect.StructField{Type: out, Tag: tag})
149
                        continue
150
                }
151
152
                // traverse all field
153
                numOfFields := out.NumField()
154
                for j := 0; j < numOfFields; j++ {
155
                        f := out.Field(j)
156
157
                        // ignore dig out
158
                        if f.Type == digOutType || f.Type == outType {
159
                                continue
160
                        }
161
162
                        d.fields = append(d.fields, f)
163
                }
164
        }
165
}
func _dig.MustDecorate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

71
func (d *_dig) MustDecorate(decorator any) DI {
72
        utils.MustSuccess(d.Container.Decorate(decorator))
73
        return d
74
}
func _dig.Decorate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

70
func (d *_dig) Decorate(decorator any) error { return d.Container.Decorate(decorator) }
func _dig.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

76
func (d *_dig) String() string {
77
        return d.Container.String()
78
}
func @46:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

46
func(p *provideOption) {
47
                p.group = group
48
        }
func Group
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/di/dig.go:

45
func Group(group string) utils.OptionFunc[provideOption] {
46
        return func(p *provideOption) {
47
                p.group = group
48
        }
49
}
Package Overview: github.com/wfusion/gofusion/common/env 61.9%

Please select a function to see what's left for testing.

GetEnv(...) github.com/wfusion/gofusion/common/env/env.go 100.0% 5/5
init(...) github.com/wfusion/gofusion/common/env/env.go 100.0% 4/4
SvcName(...) github.com/wfusion/gofusion/common/env/env.go 57.1% 4/7
IsOnline(...) github.com/wfusion/gofusion/common/env/env.go 0.0% 0/1
IsStaging(...) github.com/wfusion/gofusion/common/env/env.go 0.0% 0/1
IsCI(...) github.com/wfusion/gofusion/common/env/env.go 0.0% 0/1
SetSvcName(...) github.com/wfusion/gofusion/common/env/env.go 0.0% 0/1
IsDEV(...) github.com/wfusion/gofusion/common/env/env.go 0.0% 0/1
func GetEnv
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

22
func GetEnv() string {
23
        if env != "" {
24
                return env
25
        }
26
        if env = os.Getenv("ENV"); env == "" {
27
                env = Dev
28
        }
29
        return env
30
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

69
func init() {
70
        GetEnv()
71
        SvcName()
72
73
        dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
74
        WorkDir = dir
75
}
func SvcName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

56
func SvcName() string {
57
        if svcName != "" {
58
                return svcName
59
        }
60
        if svcName = os.Getenv("SVC_NAME"); svcName != "" {
61
                return svcName
62
        }
63
        if svcName = os.Getenv("SERVICE_NAME"); svcName != "" {
64
                return svcName
65
        }
66
        return ""
67
}
func IsOnline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

38
func IsOnline() bool {
39
        return GetEnv() == Online
40
}
func IsStaging
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

43
func IsStaging() bool {
44
        return GetEnv() == Staging
45
}
func IsCI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

48
func IsCI() bool {
49
        return GetEnv() == CI
50
}
func SetSvcName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

52
func SetSvcName(name string) {
53
        svcName = name
54
}
func IsDEV
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/env/env.go:

33
func IsDEV() bool {
34
        return GetEnv() == Dev
35
}
Package Overview: github.com/wfusion/gofusion/common/infra/drivers/mongo 89.1%

Please select a function to see what's left for testing.

defaultDialect.wrapNumberSetter(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 2/2
Mongo.GetProxy(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/interface.go 100.0% 1/1
WithMonitor(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go 100.0% 1/1
@10:9(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go 100.0% 1/1
WithPoolMonitor(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go 100.0% 1/1
@16:9(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go 100.0% 1/1
Mongo.Database(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/interface.go 100.0% 1/1
@101:39(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@102:43(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@103:45(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@104:47(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@105:49(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@106:43(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
@108:41(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
defaultDialect.parseOption(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 100.0% 1/1
defaultDialect.New(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 91.3% 21/23
defaultDialect.wrapDurationSetter(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 66.7% 4/6
@107:41(...) github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go 0.0% 0/1
func defaultDialect.wrapNumberSetter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

143
func (d *defaultDialect) wrapNumberSetter(n uint64, setter func(nu uint64)) {
144
        if n > 0 {
145
                setter(n)
146
        }
147
}
func Mongo.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/interface.go:

26
func (m *Mongo) GetProxy() *mongo.Client {
27
        return m.Client
28
}
func WithMonitor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go:

9
func WithMonitor(monitor *event.CommandMonitor) utils.OptionFunc[newOption] {
10
        return func(o *newOption) {
11
                o.monitor = monitor
12
        }
13
}
func @10:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go:

10
func(o *newOption) {
11
                o.monitor = monitor
12
        }
func WithPoolMonitor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go:

15
func WithPoolMonitor(monitor *event.PoolMonitor) utils.OptionFunc[newOption] {
16
        return func(o *newOption) {
17
                o.poolMonitor = monitor
18
        }
19
}
func @16:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/logger.go:

16
func(o *newOption) {
17
                o.poolMonitor = monitor
18
        }
func Mongo.Database
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/interface.go:

30
func (m *Mongo) Database(name string, opts ...*options.DatabaseOptions) *mongo.Database {
31
        return m.Client.Database(name, opts...)
32
}
func @101:39
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

101
func(du time.Duration) { opt.SetTimeout(du) }
func @102:43
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

102
func(du time.Duration) { opt.SetConnectTimeout(du) }
func @103:45
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

103
func(du time.Duration) { opt.SetSocketTimeout(du) }
func @104:47
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

104
func(du time.Duration) { opt.SetMaxConnIdleTime(du) }
func @105:49
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

105
func(du time.Duration) { opt.SetHeartbeatInterval(du) }
func @106:43
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

106
func(nu uint64) { opt.SetMaxConnecting(option.MaxConnecting) }
func @108:41
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

108
func(nu uint64) { opt.SetMaxPoolSize(option.MaxPoolSize) }
func defaultDialect.parseOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

149
func (d *defaultDialect) parseOption(option Option) (dsn string) {
150
        return fmt.Sprintf("mongodb://%s:%s@%s/%s?authSource=%s",
151
                option.User, option.Password, strings.Join(option.Endpoints, constant.Comma), option.DB, option.AuthDB)
152
}
func defaultDialect.New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

97
func (d *defaultDialect) New(ctx context.Context, option Option, opts ...utils.OptionExtender) (cli *Mongo, err error) {
98
        opt := options.Client().ApplyURI(d.parseOption(option))
99
        opt.SetRetryReads(option.RetryReads)
100
        opt.SetRetryWrites(option.RetryWrites)
101
        d.wrapDurationSetter(option.Timeout, func(du time.Duration) { opt.SetTimeout(du) })
102
        d.wrapDurationSetter(option.ConnTimeout, func(du time.Duration) { opt.SetConnectTimeout(du) })
103
        d.wrapDurationSetter(option.SocketTimeout, func(du time.Duration) { opt.SetSocketTimeout(du) })
104
        d.wrapDurationSetter(option.MaxConnIdleTime, func(du time.Duration) { opt.SetMaxConnIdleTime(du) })
105
        d.wrapDurationSetter(option.HeartbeatInterval, func(du time.Duration) { opt.SetHeartbeatInterval(du) })
106
        d.wrapNumberSetter(option.MaxConnecting, func(nu uint64) { opt.SetMaxConnecting(option.MaxConnecting) })
107
        d.wrapNumberSetter(option.MinPoolSize, func(nu uint64) { opt.SetMinPoolSize(option.MinPoolSize) })
108
        d.wrapNumberSetter(option.MaxPoolSize, func(nu uint64) { opt.SetMaxPoolSize(option.MaxPoolSize) })
109
110
        newOpt := utils.ApplyOptions[newOption](opts...)
111
        if newOpt.monitor != nil {
112
                opt = opt.SetMonitor(newOpt.monitor)
113
        }
114
        if newOpt.poolMonitor != nil {
115
                opt = opt.SetPoolMonitor(newOpt.poolMonitor)
116
        }
117
118
        mgoCli, err := mongo.Connect(ctx, opt)
119
        if err != nil {
120
                return
121
        }
122
123
        // authentication check
124
        if err = mgoCli.Ping(ctx, nil); err != nil {
125
                return
126
        }
127
128
        cli = &Mongo{Client: mgoCli}
129
        return
130
}
func defaultDialect.wrapDurationSetter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

132
func (d *defaultDialect) wrapDurationSetter(s string, setter func(du time.Duration)) {
133
        if utils.IsStrBlank(s) {
134
                return
135
        }
136
        duration, err := time.ParseDuration(s)
137
        if err != nil {
138
                panic(err)
139
        }
140
        setter(duration)
141
}
func @107:41
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/mongo/mongo.go:

107
func(nu uint64) { opt.SetMinPoolSize(option.MinPoolSize) }
Package Overview: github.com/wfusion/gofusion/common/infra/drivers/orm 75.3%

Please select a function to see what's left for testing.

gormDriver.parseDBOption(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 100.0% 10/10
gormDriver.genSqlServerDsn(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 100.0% 6/6
DB.WithContext(...) github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go 100.0% 2/2
gormDriver.genPostgresDsn(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 100.0% 2/2
DB.GetProxy(...) github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go 100.0% 1/1
WithLogger(...) github.com/wfusion/gofusion/common/infra/drivers/orm/logger.go 100.0% 1/1
@10:9(...) github.com/wfusion/gofusion/common/infra/drivers/orm/logger.go 100.0% 1/1
gormDriver.New(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 90.5% 19/21
gormDriver.open(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 75.0% 9/12
gormDriver.genMySqlDsn(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 66.7% 4/6
gormDriver.genClickhouseDsn(...) github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go 0.0% 0/10
DB.GetDialector(...) github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go 0.0% 0/1
func gormDriver.parseDBOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

138
func (g *gormDriver) parseDBOption(option Option) (parsed *gormDriverOption) {
139
        parsed = &gormDriverOption{
140
                Driver:       option.Driver,
141
                Dialect:      option.Dialect,
142
                Timeout:      option.Timeout,
143
                ReadTimeout:  option.ReadTimeout,
144
                WriteTimeout: option.WriteTimeout,
145
                User:         option.User,
146
                Password:     option.Password,
147
                DBName:       option.DB,
148
                DBCharset:    "utf8mb4,utf8",
149
                DBHostname:   option.Host,
150
                DBPort:       fmt.Sprintf("%v", option.Port),
151
                Scheme:       "tcp",
152
        }
153
154
        if option.Driver != "" {
155
                parsed.Driver = option.Driver
156
        }
157
        if option.MaxIdleConns > 0 {
158
                parsed.MaxIdleConns = option.MaxIdleConns
159
        }
160
        if option.MaxOpenConns > 0 {
161
                parsed.MaxOpenConns = option.MaxOpenConns
162
        }
163
164
        if utils.IsStrBlank(string(parsed.Dialect)) {
165
                parsed.Dialect = defaultDriverDialectMapping[parsed.Driver]
166
        }
167
168
        return
169
}
func gormDriver.genSqlServerDsn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

195
func (g *gormDriver) genSqlServerDsn(opt *gormDriverOption) (dsn string) {
196
        const (
197
                dsnFormat = "sqlserver://%s:%s@%s:%s?database=%s&connection+timeout=%s"
198
        )
199
200
        timeout := "5" // seconds
201
        if utils.IsStrNotBlank(opt.Timeout) {
202
                if duration, err := time.ParseDuration(opt.Timeout); err == nil {
203
                        timeout = fmt.Sprintf("%v", int(duration/time.Second))
204
                }
205
        }
206
207
        return fmt.Sprintf(dsnFormat, opt.User, opt.Password, opt.DBHostname, opt.DBPort, opt.DBName, timeout)
208
}
func DB.WithContext
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go:

52
func (d *DB) WithContext(ctx context.Context) *DB {
53
        d.DB = d.DB.WithContext(ctx)
54
        return d
55
}
func gormDriver.genPostgresDsn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

187
func (g *gormDriver) genPostgresDsn(opt *gormDriverOption) (dsn string) {
188
        const (
189
                dsnFormat = "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai"
190
        )
191
192
        return fmt.Sprintf(dsnFormat, opt.DBHostname, opt.User, opt.Password, opt.DBName, opt.DBPort)
193
}
func DB.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go:

44
func (d *DB) GetProxy() *gorm.DB {
45
        return d.DB
46
}
func WithLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/logger.go:

9
func WithLogger(l logger.Interface) utils.OptionFunc[newOption] {
10
        return func(o *newOption) {
11
                o.logger = l
12
        }
13
}
func @10:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/logger.go:

10
func(o *newOption) {
11
                o.logger = l
12
        }
func gormDriver.New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

43
func (g *gormDriver) New(ctx context.Context, option Option, opts ...utils.OptionExtender) (db *DB, err error) {
44
        opt := g.parseDBOption(option)
45
        gormDB, dialector, err := g.open(opt.Driver, string(opt.Dialect), opt)
46
        if err != nil {
47
                return
48
        }
49
50
        sqlDB, err := gormDB.DB()
51
        if err != nil {
52
                return
53
        }
54
55
        // optional
56
        if opt.MaxOpenConns > 0 {
57
                sqlDB.SetMaxOpenConns(opt.MaxOpenConns)
58
        }
59
        if opt.MaxIdleConns > 0 {
60
                sqlDB.SetMaxIdleConns(opt.MaxIdleConns)
61
        }
62
        if utils.IsStrNotBlank(option.ConnMaxLifeTime) {
63
                if liftTime, err := time.ParseDuration(option.ConnMaxLifeTime); err == nil {
64
                        sqlDB.SetConnMaxLifetime(liftTime)
65
                }
66
        }
67
        if utils.IsStrNotBlank(option.ConnMaxLifeTime) {
68
                if idleTime, err := time.ParseDuration(option.ConnMaxIdleTime); err == nil {
69
                        sqlDB.SetConnMaxIdleTime(idleTime)
70
                }
71
        }
72
73
        newOpt := utils.ApplyOptions[newOption](opts...)
74
        if newOpt.logger != nil {
75
                gormDB.Logger = newOpt.logger
76
        }
77
78
        return &DB{DB: gormDB.WithContext(ctx), dialector: dialector}, nil
79
}
func gormDriver.open
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

81
func (g *gormDriver) open(driver driver, dialect string, opt *gormDriverOption) (
82
        db *gorm.DB, dialector gorm.Dialector, err error) {
83
        // alternative driver
84
        switch driver {
85
        case DriverMysql:
86
                dialector = mysql.New(mysql.Config{
87
                        DriverName: dialect,
88
                        DSN:        g.genMySqlDsn(opt),
89
                })
90
91
        case DriverPostgres:
92
                if dialect == string(DialectOpenGauss) {
93
                        dialector = opengauss.New(opengauss.Config{
94
                                DriverName: dialect,
95
                                DSN:        g.genPostgresDsn(opt),
96
                        })
97
                } else {
98
                        dialector = postgres.New(postgres.Config{
99
                                DriverName: dialect,
100
                                DSN:        g.genPostgresDsn(opt),
101
                        })
102
                }
103
104
        // sqlite dsn is filepath
105
        // or file::memory:?cache=shared is also available, see also https://www.sqlite.org/inmemorydb.html
106
        case DriverSqlite:
107
                dialector = sqlite.Open(path.Join(env.WorkDir, path.Clean(opt.DBName)))
108
109
        case DriverSqlserver:
110
                dialector = sqlserver.New(sqlserver.Config{
111
                        DriverName: dialect,
112
                        DSN:        g.genSqlServerDsn(opt),
113
                })
114
115
        // tidb is compatible with mysql protocol
116
        case DriverTiDB:
117
                dialector = mysql.New(mysql.Config{
118
                        DriverName: dialect,
119
                        DSN:        g.genMySqlDsn(opt),
120
                })
121
122
        case DriverClickhouse:
123
                dialector = clickhouse.New(clickhouse.Config{
124
                        DriverName: dialect,
125
                        DSN:        g.genClickhouseDsn(opt),
126
                })
127
128
        default:
129
                panic(errors.Errorf("unknown db driver or dialect: %s %s", driver, dialect))
130
        }
131
132
        db, err = gorm.Open(dialector, &gorm.Config{
133
                DisableForeignKeyConstraintWhenMigrating: true,
134
        })
135
        return
136
}
func gormDriver.genMySqlDsn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

171
func (g *gormDriver) genMySqlDsn(opt *gormDriverOption) (dsn string) {
172
        if opt.DBCharset == "" {
173
                opt.DBCharset = "utf8"
174
        }
175
        if opt.Scheme == "" {
176
                opt.Scheme = "tcp"
177
        }
178
179
        const (
180
                dsnFormat = "%s:%s@%s(%s:%s)/%s?charset=%s&parseTime=True&loc=Local&timeout=%s&readTimeout=%s&writeTimeout=%s"
181
        )
182
183
        return fmt.Sprintf(dsnFormat, opt.User, opt.Password, opt.Scheme, opt.DBHostname, opt.DBPort, opt.DBName,
184
                opt.DBCharset, opt.Timeout, opt.ReadTimeout, opt.WriteTimeout)
185
}
func gormDriver.genClickhouseDsn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/gorm.go:

210
func (g *gormDriver) genClickhouseDsn(opt *gormDriverOption) (dsn string) {
211
        const (
212
                dsnFormat = "tcp://%s:%s?database=%s&username=%s&password=%s&read_timeout=%s&write_timeout=%s"
213
        )
214
215
        readTimeout := "2" // seconds
216
        if utils.IsStrNotBlank(opt.ReadTimeout) {
217
                if duration, err := time.ParseDuration(opt.ReadTimeout); err == nil {
218
                        readTimeout = fmt.Sprintf("%v", int(duration/time.Second))
219
                }
220
        }
221
        writeTimeout := "2" // seconds
222
        if utils.IsStrNotBlank(opt.ReadTimeout) {
223
                if duration, err := time.ParseDuration(opt.WriteTimeout); err == nil {
224
                        writeTimeout = fmt.Sprintf("%v", int(duration/time.Second))
225
                }
226
        }
227
228
        return fmt.Sprintf(dsnFormat, opt.DBHostname, opt.DBPort, opt.DBName, opt.User, opt.Password,
229
                readTimeout, writeTimeout)
230
}
func DB.GetDialector
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/interface.go:

48
func (d *DB) GetDialector() gorm.Dialector {
49
        return d.dialector
50
}
Package Overview: github.com/wfusion/gofusion/common/infra/drivers/orm/idgen 87.5%

Please select a function to see what's left for testing.

NewSnowflake(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go 100.0% 2/2
GormTx(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/interface.go 100.0% 1/1
snowflake.Next(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go 100.0% 1/1
@36:15(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go 93.3% 14/15
@32:19(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go 75.0% 3/4
@26:9(...) github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/interface.go 0.0% 0/1
func NewSnowflake
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go:

31
func NewSnowflake() Generator {
32
        snowflakeOnce.Do(func() {
33
                flake := sonyflake.NewSonyflake(sonyflake.Settings{
34
                        StartTime: time.Time{},
35
                        // machine id: hash(host ip + local ip + pid)(8 bit) - local ip(8 bit)
36
                        MachineID: func() (id uint16, err error) {
37
                                pid := os.Getpid()
38
                                hostIP := utils.HostIPInDocker()
39
                                localIP := utils.ClientIP()
40
                                log.Printf("[Common] snowflake get machine id base [host[%s] local[%s] pid[%v]]", hostIP, localIP, pid)
41
                                if hostIP == "" {
42
                                        hostIP = utils.ClientIP()
43
                                }
44
                                hash := fnv.New32a()
45
                                _, err = hash.Write([]byte(fmt.Sprintf("%s%s%v", hostIP, localIP, pid)))
46
                                if err != nil {
47
                                        return
48
                                }
49
50
                                high := byte(hash.Sum32() % 255)
51
                                low := net.ParseIP(localIP).To4()[3]
52
                                id = uint16(high)<<8 | uint16(low)
53
                                log.Printf("[Common] snowflake get machine id [%X]", id)
54
                                return
55
                        },
56
                        CheckMachineID: nil,
57
                })
58
                if flake == nil {
59
                        panic(ErrNewGenerator)
60
                }
61
                snowflakeInstance = &snowflake{instance: flake}
62
        })
63
64
        return snowflakeInstance
65
}
func GormTx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/interface.go:

25
func GormTx(tx *gorm.DB) utils.OptionFunc[option] {
26
        return func(o *option) {
27
                o.tx = tx
28
        }
29
}
func snowflake.Next
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go:

67
func (s *snowflake) Next(opts ...utils.OptionExtender) (id uint64, err error) {
68
        return s.instance.NextID()
69
}
func @36:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go:

36
func() (id uint16, err error) {
37
                                pid := os.Getpid()
38
                                hostIP := utils.HostIPInDocker()
39
                                localIP := utils.ClientIP()
40
                                log.Printf("[Common] snowflake get machine id base [host[%s] local[%s] pid[%v]]", hostIP, localIP, pid)
41
                                if hostIP == "" {
42
                                        hostIP = utils.ClientIP()
43
                                }
44
                                hash := fnv.New32a()
45
                                _, err = hash.Write([]byte(fmt.Sprintf("%s%s%v", hostIP, localIP, pid)))
46
                                if err != nil {
47
                                        return
48
                                }
49
50
                                high := byte(hash.Sum32() % 255)
51
                                low := net.ParseIP(localIP).To4()[3]
52
                                id = uint16(high)<<8 | uint16(low)
53
                                log.Printf("[Common] snowflake get machine id [%X]", id)
54
                                return
55
                        }
func @32:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/snowflake.go:

32
func() {
33
                flake := sonyflake.NewSonyflake(sonyflake.Settings{
34
                        StartTime: time.Time{},
35
                        // machine id: hash(host ip + local ip + pid)(8 bit) - local ip(8 bit)
36
                        MachineID: func() (id uint16, err error) {
37
                                pid := os.Getpid()
38
                                hostIP := utils.HostIPInDocker()
39
                                localIP := utils.ClientIP()
40
                                log.Printf("[Common] snowflake get machine id base [host[%s] local[%s] pid[%v]]", hostIP, localIP, pid)
41
                                if hostIP == "" {
42
                                        hostIP = utils.ClientIP()
43
                                }
44
                                hash := fnv.New32a()
45
                                _, err = hash.Write([]byte(fmt.Sprintf("%s%s%v", hostIP, localIP, pid)))
46
                                if err != nil {
47
                                        return
48
                                }
49
50
                                high := byte(hash.Sum32() % 255)
51
                                low := net.ParseIP(localIP).To4()[3]
52
                                id = uint16(high)<<8 | uint16(low)
53
                                log.Printf("[Common] snowflake get machine id [%X]", id)
54
                                return
55
                        },
56
                        CheckMachineID: nil,
57
                })
58
                if flake == nil {
59
                        panic(ErrNewGenerator)
60
                }
61
                snowflakeInstance = &snowflake{instance: flake}
62
        }
func @26:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/orm/idgen/interface.go:

26
func(o *option) {
27
                o.tx = tx
28
        }
Package Overview: github.com/wfusion/gofusion/common/infra/drivers/redis 47.1%

Please select a function to see what's left for testing.

@47:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
@10:9(...) github.com/wfusion/gofusion/common/infra/drivers/redis/hook.go 100.0% 1/1
Redis.GetProxy(...) github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go 100.0% 1/1
@48:45(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
WithHook(...) github.com/wfusion/gofusion/common/infra/drivers/redis/hook.go 100.0% 1/1
@49:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
defaultDialect.parseOption(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
@46:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
@52:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
@51:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
@50:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 100.0% 1/1
defaultDialect.wrapDurationSetter(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 83.3% 5/6
defaultDialect.New(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 48.5% 16/33
Redis.PoolStatus(...) github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go 0.0% 0/4
Redis.Close(...) github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go 0.0% 0/4
@26:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@45:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@27:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@25:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@24:48(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@23:45(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@22:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@21:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
@20:44(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
defaultDialect.parseClusterOption(...) github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go 0.0% 0/1
func @47:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

47
func(du time.Duration) { opt.ReadTimeout = du }
func @10:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/hook.go:

10
func(o *newOption) {
11
                o.hooks = append(o.hooks, hooks...)
12
        }
func Redis.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go:

86
func (r *Redis) GetProxy() redis.UniversalClient {
87
        return r.redis
88
}
func @48:45
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

48
func(du time.Duration) { opt.WriteTimeout = du }
func WithHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/hook.go:

9
func WithHook(hooks []redis.Hook) utils.OptionFunc[newOption] {
10
        return func(o *newOption) {
11
                o.hooks = append(o.hooks, hooks...)
12
        }
13
}
func @49:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

49
func(du time.Duration) { opt.ConnMaxIdleTime = du }
func defaultDialect.parseOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

81
func (d *defaultDialect) parseOption(option Option) (cfg *redis.Options) {
82
        return &redis.Options{
83
                Addr:         option.Endpoints[0],
84
                Username:     option.User,
85
                Password:     option.Password,
86
                MaxRetries:   option.MaxRetries,
87
                MinIdleConns: option.MinIdleConns,
88
                MaxIdleConns: option.MaxIdleConns,
89
                PoolSize:     option.PoolSize,
90
        }
91
}
func @46:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

46
func(du time.Duration) { opt.DialTimeout = du }
func @52:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

52
func(du time.Duration) { opt.MaxRetryBackoff = du }
func @51:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

51
func(du time.Duration) { opt.MinRetryBackoff = du }
func @50:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

50
func(du time.Duration) { opt.ConnMaxLifetime = du }
func defaultDialect.wrapDurationSetter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

70
func (d *defaultDialect) wrapDurationSetter(s string, setter func(du time.Duration)) {
71
        if utils.IsStrBlank(s) {
72
                return
73
        }
74
        duration, err := time.ParseDuration(s)
75
        if err != nil {
76
                panic(err)
77
        }
78
        setter(duration)
79
}
func defaultDialect.New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

16
func (d *defaultDialect) New(ctx context.Context, option Option, opts ...utils.OptionExtender) (
17
        r *Redis, err error) {
18
        if option.Cluster {
19
                opt := d.parseClusterOption(option)
20
                d.wrapDurationSetter(option.PoolTimeout, func(du time.Duration) { opt.PoolTimeout = du })
21
                d.wrapDurationSetter(option.DialTimeout, func(du time.Duration) { opt.DialTimeout = du })
22
                d.wrapDurationSetter(option.ReadTimeout, func(du time.Duration) { opt.ReadTimeout = du })
23
                d.wrapDurationSetter(option.WriteTimeout, func(du time.Duration) { opt.WriteTimeout = du })
24
                d.wrapDurationSetter(option.ConnMaxIdleTime, func(du time.Duration) { opt.ConnMaxIdleTime = du })
25
                d.wrapDurationSetter(option.ConnMaxLifetime, func(du time.Duration) { opt.ConnMaxLifetime = du })
26
                d.wrapDurationSetter(option.MinRetryBackoff, func(du time.Duration) { opt.MinRetryBackoff = du })
27
                d.wrapDurationSetter(option.MaxRetryBackoff, func(du time.Duration) { opt.MaxRetryBackoff = du })
28
29
                rdsCli := redis.NewClusterClient(opt)
30
31
                // authentication check
32
                if err = rdsCli.Ping(context.Background()).Err(); err != nil {
33
                        return
34
                }
35
36
                newOpt := utils.ApplyOptions[newOption](opts...)
37
                for _, hook := range newOpt.hooks {
38
                        rdsCli.AddHook(hook)
39
                }
40
41
                return &Redis{redis: rdsCli}, nil
42
43
        } else {
44
                opt := d.parseOption(option)
45
                d.wrapDurationSetter(option.PoolTimeout, func(du time.Duration) { opt.PoolTimeout = du })
46
                d.wrapDurationSetter(option.DialTimeout, func(du time.Duration) { opt.DialTimeout = du })
47
                d.wrapDurationSetter(option.ReadTimeout, func(du time.Duration) { opt.ReadTimeout = du })
48
                d.wrapDurationSetter(option.WriteTimeout, func(du time.Duration) { opt.WriteTimeout = du })
49
                d.wrapDurationSetter(option.ConnMaxIdleTime, func(du time.Duration) { opt.ConnMaxIdleTime = du })
50
                d.wrapDurationSetter(option.ConnMaxLifetime, func(du time.Duration) { opt.ConnMaxLifetime = du })
51
                d.wrapDurationSetter(option.MinRetryBackoff, func(du time.Duration) { opt.MinRetryBackoff = du })
52
                d.wrapDurationSetter(option.MaxRetryBackoff, func(du time.Duration) { opt.MaxRetryBackoff = du })
53
54
                rdsCli := redis.NewClient(opt)
55
56
                // authentication check
57
                if err = rdsCli.Ping(context.Background()).Err(); err != nil {
58
                        return
59
                }
60
61
                newOpt := utils.ApplyOptions[newOption](opts...)
62
                for _, hook := range newOpt.hooks {
63
                        rdsCli.AddHook(hook)
64
                }
65
66
                return &Redis{redis: rdsCli}, nil
67
        }
68
}
func Redis.PoolStatus
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go:

101
func (r *Redis) PoolStatus() *redis.PoolStats {
102
        switch rdsCli := r.redis.(type) {
103
        case *redis.ClusterClient:
104
                return rdsCli.PoolStats()
105
        case *redis.Client:
106
                return rdsCli.PoolStats()
107
        default:
108
                return new(redis.PoolStats)
109
        }
110
}
func Redis.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/interface.go:

90
func (r *Redis) Close() error {
91
        switch rdsCli := r.redis.(type) {
92
        case *redis.ClusterClient:
93
                return rdsCli.Close()
94
        case *redis.Client:
95
                return rdsCli.Close()
96
        default:
97
                return nil
98
        }
99
}
func @26:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

26
func(du time.Duration) { opt.MinRetryBackoff = du }
func @45:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

45
func(du time.Duration) { opt.PoolTimeout = du }
func @27:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

27
func(du time.Duration) { opt.MaxRetryBackoff = du }
func @25:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

25
func(du time.Duration) { opt.ConnMaxLifetime = du }
func @24:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

24
func(du time.Duration) { opt.ConnMaxIdleTime = du }
func @23:45
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

23
func(du time.Duration) { opt.WriteTimeout = du }
func @22:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

22
func(du time.Duration) { opt.ReadTimeout = du }
func @21:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

21
func(du time.Duration) { opt.DialTimeout = du }
func @20:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

20
func(du time.Duration) { opt.PoolTimeout = du }
func defaultDialect.parseClusterOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/infra/drivers/redis/redis.go:

93
func (d *defaultDialect) parseClusterOption(option Option) (cfg *redis.ClusterOptions) {
94
        return &redis.ClusterOptions{
95
                Addrs:        option.Endpoints,
96
                Username:     option.User,
97
                Password:     option.Password,
98
                MaxRetries:   option.MaxRetries,
99
                MinIdleConns: option.MinIdleConns,
100
                MaxIdleConns: option.MaxIdleConns,
101
                PoolSize:     option.PoolSize,
102
        }
103
}
Package Overview: github.com/wfusion/gofusion/common/utils 56.4%

Please select a function to see what's left for testing.

NginxID(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 22/22
GetCaller(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 14/14
.init(...) github.com/wfusion/gofusion/common/utils/enum.go 100.0% 12/12
FuzzyKeyword(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 10/10
@117:9(...) github.com/wfusion/gofusion/common/utils/time.go 100.0% 9/9
Set[T].Items(...) github.com/wfusion/gofusion/common/utils/sets.go 100.0% 8/8
SliceMapping(...) github.com/wfusion/gofusion/common/utils/conv.go 100.0% 6/6
MapMerge(...) github.com/wfusion/gofusion/common/utils/map.go 100.0% 6/6
poolBytes.Reset(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 5/5
Set[T].Remove(...) github.com/wfusion/gofusion/common/utils/sets.go 100.0% 5/5
Set[T].Insert(...) github.com/wfusion/gofusion/common/utils/sets.go 100.0% 5/5
ApplyOptions(...) github.com/wfusion/gofusion/common/utils/options.go 100.0% 5/5
RandomLetterAndNumber(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 5/5
@61:14(...) github.com/wfusion/gofusion/common/utils/ip.go 100.0% 5/5
@133:14(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 5/5
GetCtxAny(...) github.com/wfusion/gofusion/common/utils/context.go 100.0% 5/5
LookupByFuzzyKeyword(...) github.com/wfusion/gofusion/common/utils/candy.go 100.0% 5/5
ParseTag(...) github.com/wfusion/gofusion/common/utils/tag.go 100.0% 4/4
.Enum(...) github.com/wfusion/gofusion/common/utils/enum.go 100.0% 4/4
NewSet(...) github.com/wfusion/gofusion/common/utils/sets.go 100.0% 4/4
SliceToMap(...) github.com/wfusion/gofusion/common/utils/map.go 100.0% 4/4
@45:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 4/4
Set[T].Contains(...) github.com/wfusion/gofusion/common/utils/sets.go 100.0% 4/4
Random(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 4/4
ErrIgnore(...) github.com/wfusion/gofusion/common/utils/candy.go 100.0% 4/4
@126:11(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 4/4
SliceReverse(...) github.com/wfusion/gofusion/common/utils/slice.go 100.0% 3/3
IfAny(...) github.com/wfusion/gofusion/common/utils/candy.go 100.0% 3/3
GetGormColumnValue(...) github.com/wfusion/gofusion/common/utils/reflect.go 100.0% 3/3
@159:5(...) github.com/wfusion/gofusion/common/utils/time.go 100.0% 3/3
@89:11(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 2/2
.IsValid(...) github.com/wfusion/gofusion/common/utils/enum.go 100.0% 2/2
OptionFunc[T].applyOption(...) github.com/wfusion/gofusion/common/utils/options.go 100.0% 2/2
@182:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 2/2
MustJsonUnmarshal(...) github.com/wfusion/gofusion/common/utils/marshal.go 100.0% 2/2
@176:3(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 2/2
init(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 2/2
@190:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 2/2
NewPool(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 2/2
@34:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 2/2
WrapFunc2(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
WrapFunc1(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
@39:36(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
MustJsonMarshal(...) github.com/wfusion/gofusion/common/utils/marshal.go 100.0% 1/1
@17:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
@177:19(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 1/1
WrapFunc(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
GetFuncName(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
IsStrBlank(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
@12:30(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
IsStrNotBlank(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
CryptoRandom(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 1/1
ULID(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 1/1
ShortUUID(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 1/1
UUID(...) github.com/wfusion/gofusion/common/utils/random.go 100.0% 1/1
SkipRegexps(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
AnyPtr(...) github.com/wfusion/gofusion/common/utils/conv.go 100.0% 1/1
SkipGlobs(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
IsStrPtrNotBlank(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
SkipKnownDepth(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
@198:9(...) github.com/wfusion/gofusion/common/utils/func.go 100.0% 1/1
@40:36(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
poolBytesEvict(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
poolBytesBufferEvict(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
SetCtxAny(...) github.com/wfusion/gofusion/common/utils/context.go 100.0% 1/1
poolSealer[T].Put(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
@41:36(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
@88:14(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
@53:9(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/common/utils/string.go 100.0% 1/1
@35:9(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
PoolableEvictFunc(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
ParseTagName(...) github.com/wfusion/gofusion/common/utils/tag.go 100.0% 1/1
@16:3(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
@14:9(...) github.com/wfusion/gofusion/common/utils/tag.go 100.0% 1/1
ParseTagUnmarshalType(...) github.com/wfusion/gofusion/common/utils/tag.go 100.0% 1/1
@26:9(...) github.com/wfusion/gofusion/common/utils/tag.go 100.0% 1/1
localIP.String(...) github.com/wfusion/gofusion/common/utils/ip.go 100.0% 1/1
NextJitterIntervalFunc(...) github.com/wfusion/gofusion/common/utils/time.go 100.0% 1/1
TimeoutWg(...) github.com/wfusion/gofusion/common/utils/time.go 100.0% 1/1
@151:9(...) github.com/wfusion/gofusion/common/utils/time.go 100.0% 1/1
@20:3(...) github.com/wfusion/gofusion/common/utils/pool.go 100.0% 1/1
TraverseValue(...) github.com/wfusion/gofusion/common/utils/reflect.go 93.3% 28/30
@60:9(...) github.com/wfusion/gofusion/common/utils/ip.go 92.9% 13/14
@152:28(...) github.com/wfusion/gofusion/common/utils/reflect.go 90.0% 9/10
EmbedsType(...) github.com/wfusion/gofusion/common/utils/reflect.go 88.9% 16/18
runVariadicFunc(...) github.com/wfusion/gofusion/common/utils/func.go 87.5% 21/24
Timeout(...) github.com/wfusion/gofusion/common/utils/time.go 87.5% 7/8
Min(...) github.com/wfusion/gofusion/common/utils/compare.go 85.7% 6/7
@11:8(...) github.com/wfusion/gofusion/common/utils/candy.go 85.7% 6/7
newBuiltinLockedSource(...) github.com/wfusion/gofusion/common/utils/random.go 85.7% 6/7
MapKeys(...) github.com/wfusion/gofusion/common/utils/map.go 83.3% 5/6
IndirectType(...) github.com/wfusion/gofusion/common/utils/reflect.go 83.3% 5/6
IndirectValue(...) github.com/wfusion/gofusion/common/utils/reflect.go 83.3% 5/6
MapValues(...) github.com/wfusion/gofusion/common/utils/map.go 83.3% 5/6
ComparableToSortable(...) github.com/wfusion/gofusion/common/utils/conv.go 83.3% 5/6
.String(...) github.com/wfusion/gofusion/common/utils/enum.go 80.0% 8/10
localIP.Bytes(...) github.com/wfusion/gofusion/common/utils/ip.go 80.0% 4/5
ParseVariadicFuncResult(...) github.com/wfusion/gofusion/common/utils/func.go 77.8% 7/9
MapValuesByKeys(...) github.com/wfusion/gofusion/common/utils/map.go 77.8% 7/9
IsBlank(...) github.com/wfusion/gofusion/common/utils/reflect.go 76.9% 10/13
@34:29(...) github.com/wfusion/gofusion/common/utils/tag.go 76.9% 10/13
poolSealer[T].Get(...) github.com/wfusion/gofusion/common/utils/pool.go 75.0% 9/12
Catch(...) github.com/wfusion/gofusion/common/utils/candy.go 75.0% 9/12
ClientIP(...) github.com/wfusion/gofusion/common/utils/ip.go 75.0% 6/8
CheckIfAny(...) github.com/wfusion/gofusion/common/utils/candy.go 75.0% 3/4
NewEnumString(...) github.com/wfusion/gofusion/common/utils/enum.go 75.0% 3/4
Max(...) github.com/wfusion/gofusion/common/utils/compare.go 71.4% 5/7
TravelCtx(...) github.com/wfusion/gofusion/common/utils/context.go 71.4% 5/7
SliceConvert(...) github.com/wfusion/gofusion/common/utils/conv.go 68.2% 15/22
IsChannelClosed(...) github.com/wfusion/gofusion/common/utils/channel.go 66.7% 4/6
CloseAnyway(...) github.com/wfusion/gofusion/common/utils/candy.go 66.7% 4/6
Must(...) github.com/wfusion/gofusion/common/utils/candy.go 66.7% 2/3
.caseSensitivityConv(...) github.com/wfusion/gofusion/common/utils/enum.go 66.7% 2/3
GetTimeStamp(...) github.com/wfusion/gofusion/common/utils/time.go 66.7% 2/3
FlushAnyway(...) github.com/wfusion/gofusion/common/utils/candy.go 60.0% 3/5
Unmarshal(...) github.com/wfusion/gofusion/common/utils/marshal.go 50.0% 11/22
MustSuccess(...) github.com/wfusion/gofusion/common/utils/candy.go 50.0% 1/2
HostIPInDocker(...) github.com/wfusion/gofusion/common/utils/ip.go 42.9% 3/7
SortableToGeneric(...) github.com/wfusion/gofusion/common/utils/conv.go 7.1% 2/28
LoopWithInterval(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/22
Set[T].Equals(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/13
Set[T].IntersectsWith(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/12
@132:28(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/10
@94:28(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/10
@114:28(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/9
@100:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/9
Set[T].IsSubsetOf(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/8
@87:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/8
CryptoRandomLetterAndNumber(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/7
CryptoRandomNumbers(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/7
@75:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/7
JsonStringify[T].UnmarshalJSON(...) github.com/wfusion/gofusion/common/utils/marshal.go 0.0% 0/6
JsonStringify[T].MarshalJSON(...) github.com/wfusion/gofusion/common/utils/marshal.go 0.0% 0/6
Set[T].Filter(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/6
@64:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/6
Set[T].Reject(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/6
InvalidUnmarshalError.Error(...) github.com/wfusion/gofusion/common/utils/marshal.go 0.0% 0/5
@54:9(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/5
Heap[E].Copy(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/5
RandomNumbers(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/5
@54:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/5
@23:9(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/5
MapSliceToMap(...) github.com/wfusion/gofusion/common/utils/map.go 0.0% 0/5
DecimalPlaces(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/4
CryptoRandomBytes(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/4
UUID20(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/4
SliceRemove(...) github.com/wfusion/gofusion/common/utils/slice.go 0.0% 0/4
GetFieldByTagWithKeys(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/3
NewHeap(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/3
Set[T].Size(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/3
Set[T].Clone(...) github.com/wfusion/gofusion/common/utils/sets.go 0.0% 0/3
Heap[E].Element(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/3
IsInRange(...) github.com/wfusion/gofusion/common/utils/compare.go 0.0% 0/3
MustOk(...) github.com/wfusion/gofusion/common/utils/candy.go 0.0% 0/3
UUID22(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/2
GetFieldTagValue(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/2
IntNarrow(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
GetFieldByTag(...) github.com/wfusion/gofusion/common/utils/reflect.go 0.0% 0/2
@19:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
@20:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
@181:3(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/2
@21:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
@22:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
@29:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
IsValidTimestamp(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/2
@30:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
@31:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
_heap[E].Pop(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/2
Sort(...) github.com/wfusion/gofusion/common/utils/sort.go 0.0% 0/2
SortStable(...) github.com/wfusion/gofusion/common/utils/sort.go 0.0% 0/2
_heap[E].Push(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/2
_heap[E].Less(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/2
@32:3(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
UintNarrow(...) github.com/wfusion/gofusion/common/utils/number.go 0.0% 0/2
UnsafeBytesToString(...) github.com/wfusion/gofusion/common/utils/conv.go 0.0% 0/1
IsStrPtrBlank(...) github.com/wfusion/gofusion/common/utils/string.go 0.0% 0/1
UnsafeStringToBytes(...) github.com/wfusion/gofusion/common/utils/conv.go 0.0% 0/1
WrapFunc7(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
UUID_(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/1
sortable[E].Less(...) github.com/wfusion/gofusion/common/utils/sort.go 0.0% 0/1
sortable[E].Swap(...) github.com/wfusion/gofusion/common/utils/sort.go 0.0% 0/1
_heap[E].Swap(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
sortable[E].Len(...) github.com/wfusion/gofusion/common/utils/sort.go 0.0% 0/1
@26:9(...) github.com/wfusion/gofusion/common/utils/enum.go 0.0% 0/1
Heap[E].Push(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
ParseTagOverwrite(...) github.com/wfusion/gofusion/common/utils/tag.go 0.0% 0/1
@20:9(...) github.com/wfusion/gofusion/common/utils/tag.go 0.0% 0/1
Heap[E].Pop(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
Heap[E].Remove(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
Heap[E].Len(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
WrapFuncAny(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
GetTime(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/1
IgnoreEnumStringCase(...) github.com/wfusion/gofusion/common/utils/enum.go 0.0% 0/1
WrapFunc6(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
LoopJitterInterval(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/1
WrapFunc5(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
LoopMaxTimes(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/1
@65:9(...) github.com/wfusion/gofusion/common/utils/time.go 0.0% 0/1
NewSafeRand(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/1
WrapFunc4(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
@182:19(...) github.com/wfusion/gofusion/common/utils/random.go 0.0% 0/1
WrapFunc3(...) github.com/wfusion/gofusion/common/utils/func.go 0.0% 0/1
Error.Error(...) github.com/wfusion/gofusion/common/utils/error.go 0.0% 0/1
MustJsonMarshalString(...) github.com/wfusion/gofusion/common/utils/marshal.go 0.0% 0/1
_heap[E].Len(...) github.com/wfusion/gofusion/common/utils/heap.go 0.0% 0/1
func NginxID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

125
func NginxID() string {
126
        upper := func(c byte) byte {
127
                val := c
128
                if val >= 97 && val <= 122 {
129
                        return val - 32
130
                }
131
                return c
132
        }
133
        int2byte := func(bs []byte, val int) {
134
                size := 10
135
                l := len(bs) - 1
136
                for idx := l; idx >= 0; idx-- {
137
                        bs[idx] = byte(uint(val%size) + uint('0'))
138
                        val = val / size
139
                }
140
        }
141
142
        ret := [33]byte{}
143
        t := time.Now()
144
        year, month, day := t.Date()
145
        hour, minute, second := t.Clock()
146
        int2byte(ret[:4], year)
147
        int2byte(ret[4:6], int(month))
148
        int2byte(ret[6:8], day)
149
        int2byte(ret[8:10], hour)
150
        int2byte(ret[10:12], minute)
151
        int2byte(ret[12:14], second)
152
        copy(ret[14:26], LocalIP.Bytes())
153
        ms := t.UnixNano() / 1e6 % 1000
154
        int2byte(ret[26:29], int(ms))
155
        u32 := rand.Uint32()
156
        u32 >>= 16
157
        src := []byte{byte(u32 & 0xff), byte((u32 >> 8) & 0xff)}
158
        hex.Encode(ret[29:33], src)
159
        for idx := 29; idx < 33; idx++ {
160
                ret[idx] = upper(ret[idx])
161
        }
162
        return string(ret[:])
163
}
func GetCaller
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

204
func GetCaller(maximumCallerDepth int, opts ...OptionExtender) (frame *runtime.Frame) {
205
        opt := ApplyOptions[getCallerOption](opts...)
206
        pcs := make([]uintptr, maximumCallerDepth)
207
        depth := runtime.Callers(opt.minimumCallerDepth, pcs)
208
        frames := runtime.CallersFrames(pcs[:depth])
209
outer:
210
        for f, hasMore := frames.Next(); hasMore; f, hasMore = frames.Next() {
211
                frame = &f
212
213
                // If the caller isn't part of this package, we're done
214
                for _, skipGlob := range opt.skipGlobList {
215
                        if skipGlob.Match(f.File) {
216
                                continue outer
217
                        }
218
                }
219
                for _, s := range opt.skipRegList {
220
                        if s.MatchString(f.File) {
221
                                continue outer
222
                        }
223
                }
224
                break
225
        }
226
227
        return
228
}
func .init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

84
func (e *enumString[T, TS]) init() Enumerable[T, TS] {
85
        // get key
86
        var key any
87
        for k := range e.mapping {
88
                key = k
89
                break
90
        }
91
        e.elemType = reflect.TypeOf(key)
92
        e.elemSliceType = reflect.SliceOf(e.elemType)
93
94
        // get prefix name
95
        e.prefix = cases.Title(language.English, cases.NoLower).String(e.elemType.Name())
96
97
        // get reversed mapping
98
        e.reversedMapping = make(map[string]TS, len(e.mapping))
99
        for k, v := range e.mapping {
100
                v = e.caseSensitivityConv(v)
101
                e.reversedMapping[v] = append(e.reversedMapping[v], k)
102
        }
103
104
        return e
105
}
func FuzzyKeyword
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

36
func FuzzyKeyword(keyword string) []string {
37
        words := strings.Fields(constant.NonNumberLetterReg.ReplaceAllString(keyword, " "))
38
        compact := strings.Join(words, "")
39
        lowerWords := SliceMapping(words, func(s string) string { return strings.ToLower(s) })
40
        upperWords := SliceMapping(words, func(s string) string { return strings.ToUpper(s) })
41
        titleWords := SliceMapping(words, func(s string) string { return strings.Title(s) })
42
43
        s := NewSet(keyword)
44
        s.Insert(
45
                compact,
46
                strings.ToUpper(compact),
47
                strings.ToLower(compact),
48
                strcase.ToCamel(keyword),
49
                strcase.ToLowerCamel(keyword),
50
                strcase.ToKebab(keyword),
51
                strcase.ToSnake(keyword),
52
                strcase.ToScreamingSnake(keyword),
53
                strcase.ToScreamingKebab(keyword),
54
        )
55
        for _, delimited := range keywordFuzzyDelimited {
56
                s.Insert(
57
                        strings.Join(lowerWords, delimited),
58
                        strings.Join(upperWords, delimited),
59
                        strings.Join(titleWords, delimited),
60
                )
61
        }
62
63
        return s.Items()
64
}
func @117:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

117
func() (interval time.Duration) {
118
                // add specified ratio jitter
119
                if !symmetric {
120
                        // if ratio is 0.5
121
                        // then interval = base + random(0.5*base) <=> [base, 1.5*base)
122
                        // if ratio is 0.1
123
                        // then interval = base + random(0.1*base) <=> [base, 1.1*base)
124
                        _range := float64(base) * ratio * rand.Float64()
125
                        interval = base + time.Duration(_range)
126
                } else {
127
                        // if ratio is 0.5
128
                        // then interval = base + random(0.5*base) - 0.25*base <=> [0.75*base, 1.25*base)
129
                        // if ratio is 0.1
130
                        // then interval = base + random(0.1*base) - 0.05*base <=> [0.95*base, 1.05*base)
131
                        _range := float64(base) * ratio * rand.Float64()
132
                        interval = base + time.Duration(_range) - time.Duration(float64(base)*(ratio/2))
133
                }
134
135
                // double and clamp for next time
136
                base = time.Duration(float64(base) * exp)
137
                if base > max {
138
                        base = max
139
                }
140
                return interval
141
        }
func Set[T].Items
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

29
func (s *Set[T]) Items() []T {
30
        s.m.RLock()
31
        defer s.m.RUnlock()
32
33
        i := 0
34
        ret := make([]T, len(s.storage))
35
        for key := range s.storage {
36
                ret[i] = key
37
                i++
38
        }
39
        return ret
40
}
func SliceMapping
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

15
func SliceMapping[T, K any](s []T, mapFn func(t T) K) (d []K) {
16
        if s == nil {
17
                return
18
        }
19
        d = make([]K, 0, len(s))
20
        for _, item := range s {
21
                d = append(d, mapFn(item))
22
        }
23
        return
24
}
func MapMerge
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

40
func MapMerge[T comparable, K any](a, b map[T]K) (r map[T]K) {
41
        r = make(map[T]K, len(a)+len(b))
42
        for k, v := range a {
43
                r[k] = v
44
        }
45
        for k, v := range b {
46
                r[k] = v
47
        }
48
        return
49
}
func poolBytes.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

101
func (p poolBytes) Reset(initLen any) poolBytes {
102
        iLen := cast.ToInt(initLen)
103
        pp := p
104
        if cap(p) < cast.ToInt(iLen) {
105
                pp = make([]byte, iLen)
106
        }
107
108
        return pp[:iLen]
109
}
func Set[T].Remove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

52
func (s *Set[T]) Remove(val ...T) *Set[T] {
53
        s.m.Lock()
54
        defer s.m.Unlock()
55
56
        for _, v := range val {
57
                delete(s.storage, v)
58
        }
59
        return s
60
}
func Set[T].Insert
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

42
func (s *Set[T]) Insert(val ...T) *Set[T] {
43
        s.m.Lock()
44
        defer s.m.Unlock()
45
46
        for _, v := range val {
47
                s.storage[v] = struct{}{}
48
        }
49
        return s
50
}
func ApplyOptions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/options.go:

15
func ApplyOptions[T any](opts ...OptionExtender) (t *T) {
16
        t = new(T)
17
        for _, optional := range opts {
18
                if optional != nil {
19
                        optional.applyOption(t)
20
                }
21
        }
22
        return
23
}
func RandomLetterAndNumber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

84
func RandomLetterAndNumber(n int) string {
85
        random := make([]byte, 0, n)
86
        rand.Seed(time.Now().UnixNano())
87
        for i := 0; i < n; i++ {
88
                random = append(random, randomChars[rand.Intn(randomCharsLength)])
89
        }
90
91
        return string(random)
92
}
func @61:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

61
func(bs []byte) {
62
                        i, j := 0, len(bs)-1
63
                        for i < j {
64
                                bs[i], bs[j] = bs[j], bs[i]
65
                                i++
66
                                j--
67
                        }
68
                }
func @133:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

133
func(bs []byte, val int) {
134
                size := 10
135
                l := len(bs) - 1
136
                for idx := l; idx >= 0; idx-- {
137
                        bs[idx] = byte(uint(val%size) + uint('0'))
138
                        val = val / size
139
                }
140
        }
func GetCtxAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/context.go:

9
func GetCtxAny[T any](ctx context.Context, key string, args ...T) (val T) {
10
        if v := ctx.Value(key); v != nil {
11
                return v.(T)
12
        }
13
        if len(args) == 0 {
14
                return
15
        }
16
        return args[0]
17
}
func LookupByFuzzyKeyword
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

134
func LookupByFuzzyKeyword[T any, F lookupByFuzzyKeywordFuncType[T]](lookup F, keyword string) (v T) {
135
        fn := WrapFunc1[T](lookup)
136
        for _, k := range FuzzyKeyword(keyword) {
137
                if v = fn(k); !IsBlank(v) {
138
                        return
139
                }
140
        }
141
        return
142
}
func ParseTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

31
func ParseTag(data any, opts ...OptionExtender) (err error) {
32
        opt := ApplyOptions[parseTagOption](opts...)
33
        stepInKinds := NewSet(reflect.Struct, reflect.Array, reflect.Slice, reflect.Map)
34
        TraverseValue(data, false, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
35
                if !value.IsValid() || !value.CanSet() || !value.CanAddr() || !value.CanInterface() {
36
                        return
37
                }
38
39
                vk := value.Kind()
40
                stepIn = stepInKinds.Contains(vk) ||
41
                        (vk == reflect.Ptr && value.Elem().IsValid() && value.Elem().Kind() == reflect.Struct)
42
43
                defaultString := field.Tag.Get(opt.tag)
44
                if IsStrBlank(defaultString) || (!opt.overwrite && !IsBlank(value)) {
45
                        return
46
                }
47
48
                defaultValue := reflect.New(value.Type()).Interface()
49
                if err = Unmarshal(defaultString, defaultValue, opt.unmarshalType); err != nil {
50
                        end = true
51
                        return
52
                }
53
                value.Set(reflect.ValueOf(defaultValue).Elem())
54
                return
55
        })
56
57
        return
58
}
func .Enum
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

51
func (e *enumString[T, TS]) Enum(s string) TS {
52
        s = e.caseSensitivityConv(s)
53
        if v, ok := e.reversedMapping[s]; ok {
54
                return SliceConvert(v, e.elemSliceType).(TS)
55
        }
56
        return nil
57
}
func NewSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

12
func NewSet[T comparable](arr ...T) (s *Set[T]) {
13
        s = &Set[T]{
14
                m:       new(sync.RWMutex),
15
                storage: make(map[T]struct{}, len(arr)),
16
        }
17
        for _, item := range arr {
18
                s.storage[item] = struct{}{}
19
        }
20
        return
21
}
func SliceToMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

61
func SliceToMap[K comparable, V any](s []V, groupFn func(v V) K) (d map[K]V) {
62
        d = make(map[K]V)
63
        for _, i := range s {
64
                d[groupFn(i)] = i
65
        }
66
        return
67
}
func @45:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

45
func(a ...any) (t1 T1, t2 T2) {
46
                ret := runVariadicFunc(fn, a...)
47
                t1 = ParseVariadicFuncResult[T1](ret, 0)
48
                t2 = ParseVariadicFuncResult[T2](ret, 1)
49
                return
50
        }
func Set[T].Contains
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

62
func (s *Set[T]) Contains(val T) bool {
63
        s.m.RLock()
64
        defer s.m.RUnlock()
65
66
        _, ok := s.storage[val]
67
        return ok
68
}
func Random
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

94
func Random(b []byte, seed int64) (n int, err error) {
95
        if seed == 0 {
96
                rand.Seed(time.Now().UnixNano())
97
        } else {
98
                rand.Seed(seed)
99
        }
100
        return rand.Read(b)
101
}
func ErrIgnore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

119
func ErrIgnore(src error, ignored ...error) (dst error) {
120
        for _, target := range ignored {
121
                if errors.Is(src, target) {
122
                        return
123
                }
124
        }
125
        return src
126
}
func @126:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

126
func(c byte) byte {
127
                val := c
128
                if val >= 97 && val <= 122 {
129
                        return val - 32
130
                }
131
                return c
132
        }
func SliceReverse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/slice.go:

12
func SliceReverse[T any, TS ~[]T](s TS) {
13
        for i := len(s)/2 - 1; i >= 0; i-- {
14
                opp := len(s) - 1 - i
15
                s[i], s[opp] = s[opp], s[i]
16
        }
17
}
func IfAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

57
func IfAny(fnList ...func() bool) {
58
        for _, fn := range fnList {
59
                if fn() {
60
                        break
61
                }
62
        }
63
}
func GetGormColumnValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

150
func GetGormColumnValue(data any, column string) (columnVal reflect.Value, ok bool) {
151
        tagKey := strings.ToUpper(column)
152
        TraverseValue(data, true, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
153
                if !value.IsValid() {
154
                        return false, false
155
                }
156
                if value.Type().Kind() == reflect.Struct {
157
                        return false, true
158
                }
159
                tagSetting := schema.ParseTagSetting(field.Tag.Get("gorm"), ";")
160
                if _, ok := tagSetting[tagKey]; ok || tagSetting["COLUMN"] == column {
161
                        columnVal = value
162
                        end = true
163
                        return
164
                }
165
                return
166
        })
167
        return
168
}
func @159:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

159
func() {
160
                switch {
161
                case opt.wg != nil:
162
                        opt.wg.Wait()
163
                }
164
                wgClosed <- struct{}{}
165
        }
func @89:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

89
func() {
90
                        if p.option.evict == nil || !p.option.evict(obj) {
91
                                p.Put(obj)
92
                        }
93
                }
func .IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

79
func (e *enumString[T, TS]) IsValid(t T) bool {
80
        _, ok := e.mapping[t]
81
        return ok
82
}
func OptionFunc[T].applyOption
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/options.go:

9
func (o OptionFunc[T]) applyOption(a any) {
10
        if t, ok := a.(*T); ok {
11
                o(t)
12
        }
13
}
func @182:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

182
func(o *getCallerOption) {
183
                for _, pattern := range patterns {
184
                        o.skipRegList = append(o.skipRegList, regexp.MustCompile(pattern))
185
                }
186
        }
func MustJsonUnmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

43
func MustJsonUnmarshal[T any](s []byte) (t *T) { MustSuccess(json.Unmarshal(s, &t)); return }
func @176:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

176
func() bool {
177
                        _, err = Catch(func() { inspect.SetField(source, "src", rand.NewSource(seed)) })
178
                        return err == nil
179
                }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

193
func init() {
194
        rand.Seed(time.Now().Unix())
195
196
        // assert if rand.lockedSource struct is not changed
197
        newBuiltinLockedSource(1).Int63()
198
}
func @190:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

190
func(o *getCallerOption) {
191
                for _, pattern := range patterns {
192
                        o.skipGlobList = append(o.skipGlobList, glob.MustCompile(pattern))
193
                }
194
        }
func NewPool
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

47
func NewPool[T any](newFn func() T, opts ...OptionExtender) Poolable[T] {
48
        opt := ApplyOptions[poolableOption[T]](opts...)
49
        return &poolSealer[T]{
50
                option: opt,
51
                newFn:  newFn,
52
                inner: &sync.Pool{
53
                        New: func() any {
54
                                return any(newFn())
55
                        },
56
                },
57
        }
58
}
func @34:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

34
func(a ...any) (t T) {
35
                ret := runVariadicFunc(fn, a...)
36
                return ParseVariadicFuncResult[T](ret, 0)
37
        }
func WrapFunc2
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

44
func WrapFunc2[T1, T2 any](fn any) func(...any) (T1, T2) {
45
        return func(a ...any) (t1 T1, t2 T2) {
46
                ret := runVariadicFunc(fn, a...)
47
                t1 = ParseVariadicFuncResult[T1](ret, 0)
48
                t2 = ParseVariadicFuncResult[T2](ret, 1)
49
                return
50
        }
51
}
func WrapFunc1
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

33
func WrapFunc1[T any](fn any) func(...any) T {
34
        return func(a ...any) (t T) {
35
                ret := runVariadicFunc(fn, a...)
36
                return ParseVariadicFuncResult[T](ret, 0)
37
        }
38
}
func @39:36
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

39
func(s string) string { return strings.ToLower(s) }
func MustJsonMarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

41
func MustJsonMarshal(s any) []byte             { return Must(json.Marshal(s)) }
func @17:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

17
func(a ...any) {
18
                runVariadicFunc(fn, a...)
19
        }
func @177:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

177
func() { inspect.SetField(source, "src", rand.NewSource(seed)) }
func WrapFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

16
func WrapFunc(fn any) func(...any) {
17
        return func(a ...any) {
18
                runVariadicFunc(fn, a...)
19
        }
20
}
func GetFuncName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

12
func GetFuncName(fn any) string {
13
        return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
14
}
func IsStrBlank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

11
func IsStrBlank(s string) bool {
12
        return strings.IndexFunc(s, func(r rune) bool { return !(unicode.IsSpace(r)) }) < 0
13
}
func @12:30
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

12
func(r rune) bool { return !(unicode.IsSpace(r)) }
func IsStrNotBlank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

19
func IsStrNotBlank(s string) bool {
20
        return !IsStrBlank(s)
21
}
func CryptoRandom
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

59
func CryptoRandom(b []byte) (n int, err error) {
60
        return cryptoRand.Read(b)
61
}
func ULID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

38
func ULID() string {
39
        return ulid.MustNew(ulid.Now(), cryptoRand.Reader).String()
40
}
func ShortUUID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

33
func ShortUUID() string {
34
        return shortuuid.New()
35
}
func UUID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

22
func UUID() string {
23
        return uuid.New().String()
24
}
func SkipRegexps
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

181
func SkipRegexps(patterns ...string) OptionFunc[getCallerOption] {
182
        return func(o *getCallerOption) {
183
                for _, pattern := range patterns {
184
                        o.skipRegList = append(o.skipRegList, regexp.MustCompile(pattern))
185
                }
186
        }
187
}
func AnyPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

145
func AnyPtr[T any](s T) *T { return &s }
func SkipGlobs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

189
func SkipGlobs(patterns ...string) OptionFunc[getCallerOption] {
190
        return func(o *getCallerOption) {
191
                for _, pattern := range patterns {
192
                        o.skipGlobList = append(o.skipGlobList, glob.MustCompile(pattern))
193
                }
194
        }
195
}
func IsStrPtrNotBlank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

23
func IsStrPtrNotBlank(s *string) bool {
24
        return s != nil && IsStrNotBlank(*s)
25
}
func SkipKnownDepth
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

197
func SkipKnownDepth(minimumCallerDepth int) OptionFunc[getCallerOption] {
198
        return func(o *getCallerOption) {
199
                o.minimumCallerDepth = minimumCallerDepth
200
        }
201
}
func @198:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

198
func(o *getCallerOption) {
199
                o.minimumCallerDepth = minimumCallerDepth
200
        }
func @40:36
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

40
func(s string) string { return strings.ToUpper(s) }
func poolBytesEvict
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

115
func poolBytesEvict(p poolBytes) bool {
116
        return cap(p) >= maxBytesPoolable
117
}
func poolBytesBufferEvict
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

111
func poolBytesBufferEvict(b *bytes.Buffer) bool {
112
        return b.Cap() >= maxBytesPoolable
113
}
func SetCtxAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/context.go:

20
func SetCtxAny[T any](ctx context.Context, key string, val T) context.Context {
21
        return context.WithValue(ctx, key, val)
22
}
func poolSealer[T].Put
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

97
func (p *poolSealer[T]) Put(obj T) { p.inner.Put(obj) }
func @41:36
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

41
func(s string) string { return strings.Title(s) }
func @88:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

88
func() {
89
                once.Do(func() {
90
                        if p.option.evict == nil || !p.option.evict(obj) {
91
                                p.Put(obj)
92
                        }
93
                })
94
        }
func @53:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

53
func() any {
54
                                return any(newFn())
55
                        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

66
func init() {
67
        strcase.ConfigureAcronym("I18n", "i18n")
68
}
func @35:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

35
func(o *poolableOption[T]) {
36
                o.evict = fn
37
        }
func PoolableEvictFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

34
func PoolableEvictFunc[T any](fn func(obj T) bool) OptionFunc[poolableOption[T]] {
35
        return func(o *poolableOption[T]) {
36
                o.evict = fn
37
        }
38
}
func ParseTagName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

13
func ParseTagName(tag string) OptionFunc[parseTagOption] {
14
        return func(o *parseTagOption) {
15
                o.tag = tag
16
        }
17
}
func @16:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

16
func() *bytes.Buffer { return bytes.NewBuffer(make([]byte, 0, 64)) }
func @14:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

14
func(o *parseTagOption) {
15
                o.tag = tag
16
        }
func ParseTagUnmarshalType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

25
func ParseTagUnmarshalType(unmarshalTag unmarshalType) OptionFunc[parseTagOption] {
26
        return func(o *parseTagOption) {
27
                o.unmarshalType = unmarshalTag
28
        }
29
}
func @26:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

26
func(o *parseTagOption) {
27
                o.unmarshalType = unmarshalTag
28
        }
func localIP.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

54
func (l *localIP) String() string {
55
        return l.str
56
}
func NextJitterIntervalFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

116
func NextJitterIntervalFunc(base, max time.Duration, ratio, exp float64, symmetric bool) func() time.Duration {
117
        return func() (interval time.Duration) {
118
                // add specified ratio jitter
119
                if !symmetric {
120
                        // if ratio is 0.5
121
                        // then interval = base + random(0.5*base) <=> [base, 1.5*base)
122
                        // if ratio is 0.1
123
                        // then interval = base + random(0.1*base) <=> [base, 1.1*base)
124
                        _range := float64(base) * ratio * rand.Float64()
125
                        interval = base + time.Duration(_range)
126
                } else {
127
                        // if ratio is 0.5
128
                        // then interval = base + random(0.5*base) - 0.25*base <=> [0.75*base, 1.25*base)
129
                        // if ratio is 0.1
130
                        // then interval = base + random(0.1*base) - 0.05*base <=> [0.95*base, 1.05*base)
131
                        _range := float64(base) * ratio * rand.Float64()
132
                        interval = base + time.Duration(_range) - time.Duration(float64(base)*(ratio/2))
133
                }
134
135
                // double and clamp for next time
136
                base = time.Duration(float64(base) * exp)
137
                if base > max {
138
                        base = max
139
                }
140
                return interval
141
        }
142
}
func TimeoutWg
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

150
func TimeoutWg(wg *sync.WaitGroup) OptionFunc[timeoutOption] {
151
        return func(o *timeoutOption) {
152
                o.wg = wg
153
        }
154
}
func @151:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

151
func(o *timeoutOption) {
152
                o.wg = wg
153
        }
func @20:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

20
func() poolBytes { return make([]byte, 0, 64) }
func TraverseValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

43
func TraverseValue(data any, indirect bool, handler func(reflect.StructField, reflect.Value) (end, stepIn bool)) {
44
        v, ok := data.(reflect.Value)
45
        if !ok {
46
                v = reflect.ValueOf(data)
47
        }
48
        v = IndirectValue(v)
49
        l := list.New()
50
        l.PushBack(v)
51
TraverseStruct:
52
        for l.Len() > 0 {
53
                e := IndirectValue(l.Remove(l.Front()).(reflect.Value))
54
                if !e.IsValid() {
55
                        continue
56
                }
57
                t := IndirectType(e.Type())
58
                switch e.Kind() {
59
                case reflect.Array, reflect.Slice:
60
                        for i, num := 0, e.Len(); i < num; i++ {
61
                                l.PushBack(e.Index(i))
62
                        }
63
                case reflect.Map:
64
                        for iter := e.MapRange(); iter.Next(); {
65
                                l.PushBack(iter.Key())
66
                                l.PushBack(iter.Value())
67
                        }
68
                case reflect.Struct:
69
                        for i, num := 0, e.NumField(); i < num; i++ {
70
                                ff := t.Field(i)
71
                                fv := e.Field(i)
72
                                if !fv.IsValid() {
73
                                        continue
74
                                }
75
                                if indirect {
76
                                        fv = IndirectValue(fv)
77
                                        ff.Type = IndirectType(ff.Type)
78
                                }
79
                                end, stepIn := handler(ff, fv)
80
                                if end {
81
                                        break TraverseStruct
82
                                }
83
                                if stepIn {
84
                                        l.PushBack(fv)
85
                                }
86
                        }
87
                default:
88
                        // do nothing
89
                }
90
        }
91
}
func @60:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

60
func() []byte {
61
                reverse := func(bs []byte) {
62
                        i, j := 0, len(bs)-1
63
                        for i < j {
64
                                bs[i], bs[j] = bs[j], bs[i]
65
                                i++
66
                                j--
67
                        }
68
                }
69
70
                if ipAddr := ClientIP(); ipAddr != "" {
71
                        realIP := []byte("000000000000")
72
                        idx := 0
73
                        for i := len(ipAddr) - 1; i >= 0; i-- {
74
                                c := ipAddr[i]
75
                                if c == '.' {
76
                                        idx = (((idx - 1) / 3) + 1) * 3
77
                                        continue
78
                                }
79
                                realIP[idx] = c
80
                                idx++
81
                        }
82
                        reverse(realIP)
83
                        return realIP
84
                }
85
                return []byte("000000000000")
86
        }
func @152:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

152
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
153
                if !value.IsValid() {
154
                        return false, false
155
                }
156
                if value.Type().Kind() == reflect.Struct {
157
                        return false, true
158
                }
159
                tagSetting := schema.ParseTagSetting(field.Tag.Get("gorm"), ";")
160
                if _, ok := tagSetting[tagKey]; ok || tagSetting["COLUMN"] == column {
161
                        columnVal = value
162
                        end = true
163
                        return
164
                }
165
                return
166
        }
func EmbedsType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

172
func EmbedsType(i any, e reflect.Type) bool {
173
        // given `type A foo { *In }`, this function would return false for
174
        // embedding dig.In, which makes for some extra error checking in places
175
        // that call this function. Might be worthwhile to consider reflect.Indirect
176
        // usage to clean up the callers.
177
178
        if i == nil {
179
                return false
180
        }
181
182
        // maybe it's already a reflect.Type
183
        t, ok := i.(reflect.Type)
184
        if !ok {
185
                // take the type if it's not
186
                t = IndirectType(reflect.TypeOf(i))
187
        }
188
189
        // We are going to do a breadth-first search of all embedded fields.
190
        types := list.New()
191
        types.PushBack(t)
192
        for types.Len() > 0 {
193
                t := types.Remove(types.Front()).(reflect.Type)
194
195
                if t == e {
196
                        return true
197
                }
198
199
                if t.Kind() != reflect.Struct {
200
                        continue
201
                }
202
203
                for i := 0; i < t.NumField(); i++ {
204
                        f := t.Field(i)
205
                        if f.Anonymous {
206
                                types.PushBack(f.Type)
207
                        }
208
                }
209
        }
210
211
        return false
212
}
func runVariadicFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

113
func runVariadicFunc(fn any, a ...any) []reflect.Value {
114
        var (
115
                variadic   []reflect.Value
116
                typ        = reflect.TypeOf(fn)
117
                val        = reflect.ValueOf(fn)
118
                numIn      = typ.NumIn()
119
                isVariadic = typ.IsVariadic()
120
        )
121
122
        if isVariadic {
123
                b := a[numIn-1:]
124
                bt := typ.In(numIn - 1).Elem()
125
                variadic = make([]reflect.Value, 0, len(b))
126
                for _, param := range b {
127
                        paramVal := reflect.ValueOf(param)
128
                        if paramVal.CanConvert(bt) {
129
                                variadic = append(variadic, paramVal.Convert(bt))
130
                        } else {
131
                                bo := reflect.New(bt).Elem().Interface()
132
                                MustSuccess(mapstructure.Decode(param, &bo))
133
                                variadic = append(variadic, reflect.ValueOf(bo))
134
                        }
135
                }
136
                a = a[:numIn-1]
137
        }
138
139
        in := make([]reflect.Value, 0, len(a)+len(variadic))
140
        for idx, param := range a {
141
                pt := typ.In(idx)
142
                paramVal := reflect.ValueOf(param)
143
                if paramVal.CanConvert(pt) {
144
                        in = append(in, paramVal.Convert(pt))
145
                } else {
146
                        po := reflect.New(pt).Elem().Interface()
147
                        MustSuccess(mapstructure.Decode(param, &po))
148
                        in = append(in, reflect.ValueOf(po))
149
                }
150
        }
151
        in = append(in, variadic...)
152
153
        return val.Call(in)
154
}
func Timeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

156
func Timeout(timeout time.Duration, opts ...OptionExtender) bool {
157
        opt := ApplyOptions[timeoutOption](opts...)
158
        wgClosed := make(chan struct{}, 1)
159
        go func() {
160
                switch {
161
                case opt.wg != nil:
162
                        opt.wg.Wait()
163
                }
164
                wgClosed <- struct{}{}
165
        }()
166
167
        timer := time.NewTimer(timeout)
168
        defer timer.Stop()
169
        select {
170
        case <-wgClosed:
171
                return false
172
        case <-timer.C:
173
                return true
174
        }
175
}
func Min
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compare.go:

28
func Min[T constraint.Sortable](arr ...T) T {
29
        if len(arr) == 0 {
30
                panic(ErrEmptyArray)
31
        }
32
33
        min := arr[0]
34
        for i := 1; i < len(arr); i++ {
35
                if arr[i] < min {
36
                        min = arr[i]
37
                }
38
        }
39
40
        return min
41
}
func @11:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

11
func() {
12
                r := recover()
13
                if r == nil {
14
                        return
15
                }
16
17
                isPanic = true
18
                switch v := r.(type) {
19
                case error:
20
                        err = errors.Wrapf(v, "panic when call Catch function =>\n%s", debug.Stack())
21
                default:
22
                        err = errors.Errorf("panic when call Catch function: %s =>\n%s", r, debug.Stack())
23
                }
24
        }
func newBuiltinLockedSource
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

169
func newBuiltinLockedSource(seed int64) rand.Source64 {
170
        t := inspect.TypeOf("math/rand.lockedSource")
171
        source := reflect.New(t).Interface()
172
173
        var err error
174
        IfAny(
175
                // go1.16 - go1.19
176
                func() bool {
177
                        _, err = Catch(func() { inspect.SetField(source, "src", rand.NewSource(seed)) })
178
                        return err == nil
179
                },
180
                // go1.20 - go1.21, source is renamed and set seed when calling rather than constructing stage
181
                func() bool {
182
                        _, err = Catch(func() { inspect.SetField(source, "s", rand.NewSource(seed)) })
183
                        return err == nil
184
                },
185
        )
186
        if err != nil {
187
                panic(err)
188
        }
189
190
        return source.(rand.Source64)
191
}
func MapKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

3
func MapKeys[T comparable, K any](m map[T]K) (keys []T) {
4
        if m == nil {
5
                return
6
        }
7
        keys = make([]T, 0, len(m))
8
        for key := range m {
9
                keys = append(keys, key)
10
        }
11
        return
12
}
func IndirectType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

225
func IndirectType(s reflect.Type) (d reflect.Type) {
226
        if s == nil {
227
                return s
228
        }
229
        d = s
230
        for d.Kind() == reflect.Ptr {
231
                d = d.Elem()
232
        }
233
        return
234
}
func IndirectValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

214
func IndirectValue(s reflect.Value) (d reflect.Value) {
215
        if !s.IsValid() {
216
                return s
217
        }
218
        d = s
219
        for d.Kind() == reflect.Ptr {
220
                d = d.Elem()
221
        }
222
        return
223
}
func MapValues
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

14
func MapValues[T comparable, K any](m map[T]K) (vals []K) {
15
        if m == nil {
16
                return
17
        }
18
        vals = make([]K, 0, len(m))
19
        for _, val := range m {
20
                vals = append(vals, val)
21
        }
22
        return
23
}
func ComparableToSortable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

96
func ComparableToSortable[T comparable](s T) (d any) {
97
        val := reflect.ValueOf(s)
98
        typ := val.Type()
99
        for _, sortableType := range sortableReflectType {
100
                if typ.ConvertibleTo(sortableType) {
101
                        return val.Convert(sortableType).Interface()
102
                }
103
        }
104
105
        return
106
}
func .String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

59
func (e *enumString[T, TS]) String(k any) string {
60
        if reflect.TypeOf(k).ConvertibleTo(e.elemType) {
61
                k = reflect.ValueOf(k).Convert(e.elemType).Interface().(T)
62
        }
63
        if t, ok := k.(T); !ok {
64
                return fmt.Sprintf("%s(%v)", e.prefix, k)
65
        } else {
66
                if v, ok := e.mapping[t]; ok {
67
                        return v
68
                }
69
                // avoid stack overflow for Stringer implement
70
                sortable := ComparableToSortable(t)
71
                if sortable != nil {
72
                        return fmt.Sprintf("%s(%+v)", e.prefix, sortable)
73
                } else {
74
                        return fmt.Sprintf("%s(N/A)", e.prefix)
75
                }
76
        }
77
}
func localIP.Bytes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

45
func (l *localIP) Bytes() (d []byte) {
46
        if l.bytes == nil {
47
                return
48
        }
49
        d = make([]byte, len(l.bytes), cap(l.bytes))
50
        copy(d, l.bytes)
51
        return
52
}
func ParseVariadicFuncResult
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

156
func ParseVariadicFuncResult[T any](rs []reflect.Value, idx int) (t T) {
157
        var (
158
                ok  bool
159
                typ = reflect.TypeOf(t)
160
        )
161
        for i := idx; i < len(rs); i++ {
162
                r := rs[i]
163
                if !r.IsValid() || r.Type() == nil {
164
                        continue
165
                }
166
                if v := r.Interface(); v != nil {
167
                        if t, ok = v.(T); !ok && typ != nil && reflect.TypeOf(v).ConvertibleTo(typ) {
168
                                t = r.Convert(typ).Interface().(T)
169
                        }
170
                }
171
        }
172
        return
173
}
func MapValuesByKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

25
func MapValuesByKeys[T comparable, K any, TS ~[]T](m map[T]K, keys TS) (vals []K) {
26
        if m == nil {
27
                return
28
        }
29
        vals = make([]K, 0, len(keys))
30
        for _, key := range keys {
31
                val, ok := m[key]
32
                if !ok {
33
                        continue
34
                }
35
                vals = append(vals, val)
36
        }
37
        return
38
}
func IsBlank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

14
func IsBlank(object any) bool {
15
        // get nil case out of the way
16
        if object == nil {
17
                return true
18
        }
19
20
        objVal, ok := object.(reflect.Value)
21
        if !ok {
22
                objVal = reflect.ValueOf(object)
23
        }
24
        switch objVal.Kind() {
25
        // collection types are empty when they have no element
26
        case reflect.Chan, reflect.Map, reflect.Slice:
27
                return objVal.Len() == 0
28
        // pointers are empty if nil or if the value they point to is empty
29
        case reflect.Ptr:
30
                if objVal.IsNil() {
31
                        return true
32
                }
33
                deref := objVal.Elem().Interface()
34
                return IsBlank(deref)
35
        // for all other types, compare against the zero value
36
        // array types are empty when they match their zero-initialized state
37
        default:
38
                zero := reflect.Zero(objVal.Type())
39
                return reflect.DeepEqual(objVal.Interface(), zero.Interface())
40
        }
41
}
func @34:29
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

34
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
35
                if !value.IsValid() || !value.CanSet() || !value.CanAddr() || !value.CanInterface() {
36
                        return
37
                }
38
39
                vk := value.Kind()
40
                stepIn = stepInKinds.Contains(vk) ||
41
                        (vk == reflect.Ptr && value.Elem().IsValid() && value.Elem().Kind() == reflect.Struct)
42
43
                defaultString := field.Tag.Get(opt.tag)
44
                if IsStrBlank(defaultString) || (!opt.overwrite && !IsBlank(value)) {
45
                        return
46
                }
47
48
                defaultValue := reflect.New(value.Type()).Interface()
49
                if err = Unmarshal(defaultString, defaultValue, opt.unmarshalType); err != nil {
50
                        end = true
51
                        return
52
                }
53
                value.Set(reflect.ValueOf(defaultValue).Elem())
54
                return
55
        }
func poolSealer[T].Get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/pool.go:

66
func (p *poolSealer[T]) Get(initialized any) (T, func()) {
67
        obj, ok := p.inner.Get().(T)
68
        if !ok {
69
                obj = p.newFn()
70
        }
71
72
        switch resettable := any(obj).(type) {
73
        case poolResettableA[T]:
74
                obj = resettable.Reset(initialized)
75
        case poolResettableB:
76
                resettable.Reset()
77
        case poolResettableC:
78
                MustSuccess(resettable.Reset())
79
        case poolResettableD:
80
                resettable.Reset(initialized)
81
        case poolResettableE:
82
                MustSuccess(resettable.Reset(initialized))
83
        case poolResettableF[T]:
84
                obj = resettable.Reset()
85
        }
86
87
        once := new(sync.Once)
88
        return obj, func() {
89
                once.Do(func() {
90
                        if p.option.evict == nil || !p.option.evict(obj) {
91
                                p.Put(obj)
92
                        }
93
                })
94
        }
95
}
func Catch
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

10
func Catch(fn any) (isPanic bool, err error) {
11
        defer func() {
12
                r := recover()
13
                if r == nil {
14
                        return
15
                }
16
17
                isPanic = true
18
                switch v := r.(type) {
19
                case error:
20
                        err = errors.Wrapf(v, "panic when call Catch function =>\n%s", debug.Stack())
21
                default:
22
                        err = errors.Errorf("panic when call Catch function: %s =>\n%s", r, debug.Stack())
23
                }
24
        }()
25
26
        // check supported function
27
        var v any
28
        switch f := fn.(type) {
29
        case func():
30
                f()
31
        case func() error:
32
                err = f()
33
        case func() (any, error):
34
                v, err = f()
35
        default:
36
                panic(errors.Errorf("unsupported function signature %T", fn))
37
        }
38
39
        if err != nil {
40
                return
41
        }
42
        if ve, ok := v.(error); ok {
43
                err = ve
44
        }
45
        return
46
}
func ClientIP
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

7
func ClientIP() (ip string) {
8
        addrs, err := net.InterfaceAddrs()
9
        if err != nil {
10
                panic(err)
11
        }
12
13
        for _, address := range addrs {
14
                if addr, ok := address.(*net.IPNet); ok && !addr.IP.IsLoopback() {
15
                        if addr.IP.To4() != nil {
16
                                return addr.IP.String()
17
                        }
18
19
                }
20
        }
21
22
        return
23
}
func CheckIfAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

48
func CheckIfAny(fnList ...func() error) error {
49
        for _, fn := range fnList {
50
                if err := fn(); err != nil {
51
                        return err
52
                }
53
        }
54
        return nil
55
}
func NewEnumString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

31
func NewEnumString[T comparable, TS ~[]T](mapping map[T]string, opts ...OptionExtender) Enumerable[T, TS] {
32
        opt := ApplyOptions[enumStringOption](opts...)
33
        if len(mapping) == 0 {
34
                panic(errors.New("enum mapping is empty"))
35
        }
36
        return (&enumString[T, TS]{
37
                mapping:    mapping,
38
                ignoreCase: opt.ignoreCaseSensitivity,
39
        }).init()
40
}
func Max
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compare.go:

13
func Max[T constraint.Sortable](arr ...T) T {
14
        if len(arr) == 0 {
15
                panic(ErrEmptyArray)
16
        }
17
18
        max := arr[0]
19
        for i := 1; i < len(arr); i++ {
20
                if arr[i] > max {
21
                        max = arr[i]
22
                }
23
        }
24
25
        return max
26
}
func TravelCtx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/context.go:

25
func TravelCtx(child context.Context, fn func(ctx context.Context) bool) {
26
        v := reflect.ValueOf(child)
27
        for p := v; p.IsValid() && p.CanInterface(); p = p.FieldByName("Context") {
28
                parent, ok := p.Interface().(context.Context)
29
                if !ok || parent == nil || fn(parent) {
30
                        break
31
                }
32
                if p = reflect.Indirect(p); p.Kind() != reflect.Struct {
33
                        break
34
                }
35
        }
36
}
func SliceConvert
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

109
func SliceConvert(src any, dstType reflect.Type) any {
110
        srcVal := reflect.ValueOf(src)
111
        srcType := reflect.TypeOf(src)
112
        dstVal := reflect.Indirect(reflect.New(dstType))
113
        if srcType.Kind() != reflect.Slice || dstType.Kind() != reflect.Slice {
114
                panic(errors.Errorf("src or dst type is invalid [src[%s] dst[%s]]", srcType.Kind(), dstType.Kind()))
115
        }
116
117
        isInterfaceSlice := false
118
        srcElemType := srcType.Elem()
119
        if srcType == constant.AnySliceType {
120
                if srcVal.Len() == 0 {
121
                        return dstVal.Interface()
122
                }
123
                srcElemType = reflect.TypeOf(srcVal.Index(0).Interface())
124
                isInterfaceSlice = true
125
        }
126
127
        dstElemType := dstType.Elem()
128
        if !srcElemType.ConvertibleTo(dstElemType) {
129
                panic(errors.Errorf("src elem is not convertible to dst elem [src[%s] dst[%s]]",
130
                        srcElemType.Kind(), dstElemType.Kind()))
131
        }
132
133
        length := srcVal.Len()
134
        for i := 0; i < length; i++ {
135
                srcElem := srcVal.Index(i)
136
                if isInterfaceSlice {
137
                        srcElem = reflect.ValueOf(srcVal.Index(i).Interface())
138
                }
139
                dstVal = reflect.Append(dstVal, srcElem.Convert(dstElemType))
140
        }
141
142
        return dstVal.Interface()
143
}
func IsChannelClosed
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/channel.go:

3
func IsChannelClosed[T any](ch <-chan T) (data T, ok bool) {
4
        select {
5
        case d, closed := <-ch:
6
                if closed {
7
                        ok = true
8
                        return
9
                }
10
                return d, false
11
        default:
12
                return
13
        }
14
}
func CloseAnyway
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

88
func CloseAnyway[T any](closer T) {
89
        if any(closer) == nil {
90
                return
91
        }
92
93
        switch c := any(closer).(type) {
94
        case io.Closer:
95
                _ = c.Close()
96
        case closerA:
97
                c.Close()
98
        case closerB[T]:
99
                c.Close()
100
        }
101
}
func Must
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

71
func Must[T any](out T, err error) T {
72
        if err != nil {
73
                panic(err)
74
        }
75
        return out
76
}
func .caseSensitivityConv
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

107
func (e *enumString[T, TS]) caseSensitivityConv(s string) string {
108
        if e.ignoreCase {
109
                return strings.ToLower(s)
110
        }
111
        return s
112
}
func GetTimeStamp
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

30
func GetTimeStamp(t time.Time) int64 {
31
        if year := t.Year(); year >= maxYear || year < minYear {
32
                return t.Unix() * 1e3
33
        }
34
        return t.UnixNano() / 1e6
35
}
func FlushAnyway
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

106
func FlushAnyway[T any](flusher T) {
107
        if any(flusher) == nil {
108
                return
109
        }
110
111
        switch f := any(flusher).(type) {
112
        case flusherA:
113
                f.Flush()
114
        case flusherB:
115
                _ = f.Flush()
116
        }
117
}
func Unmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

70
func Unmarshal(s, d any, tag unmarshalType) (err error) {
71
        switch s.(type) {
72
        case string, []byte:
73
                bs, cb := BytesBufferPool.Get(nil)
74
                defer cb()
75
                if ss, ok := s.(string); ok {
76
                        bs.WriteString(ss)
77
                } else {
78
                        bs.Write(s.([]byte))
79
                }
80
81
                switch tag {
82
                case UnmarshalTypeJson:
83
                        return json.NewDecoder(bs).Decode(d)
84
                case UnmarshalTypeYaml:
85
                        err = yaml.NewDecoder(bs).Decode(d)
86
                        return
87
                case UnmarshalTypeToml:
88
                        _, err = toml.NewDecoder(bs).Decode(d)
89
                        return
90
                default:
91
                        err = gob.NewDecoder(bs).Decode(d)
92
                        return
93
                }
94
        default:
95
                cfg := &mapstructure.DecoderConfig{Result: d}
96
                if tag != "" {
97
                        cfg.TagName = string(tag)
98
                }
99
100
                var dec *mapstructure.Decoder
101
                if dec, err = mapstructure.NewDecoder(cfg); err != nil {
102
                        return
103
                }
104
                err = dec.Decode(s)
105
                return
106
        }
107
}
func MustSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

65
func MustSuccess(err error) {
66
        if err != nil {
67
                panic(err)
68
        }
69
}
func HostIPInDocker
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/ip.go:

25
func HostIPInDocker() (ip string) {
26
        addrs, err := net.LookupIP("host.docker.internal")
27
        if err != nil {
28
                return
29
        }
30
31
        for _, addr := range addrs {
32
                if addr.To4() != nil {
33
                        return addr.String()
34
                }
35
        }
36
        return
37
}
func SortableToGeneric
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

27
func SortableToGeneric[T, K constraint.Sortable](s T) (d K) {
28
        switch any(d).(type) {
29
        case int:
30
                return any(cast.ToInt(s)).(K)
31
        case int8:
32
                return any(cast.ToInt8(s)).(K)
33
        case int16:
34
                return any(cast.ToInt16(s)).(K)
35
        case int32:
36
                return any(cast.ToInt32(s)).(K)
37
        case int64:
38
                return any(cast.ToInt64(s)).(K)
39
        case *int:
40
                return any(AnyPtr(cast.ToInt(s))).(K)
41
        case *int8:
42
                return any(AnyPtr(cast.ToInt8(s))).(K)
43
        case *int16:
44
                return any(AnyPtr(cast.ToInt16(s))).(K)
45
        case *int32:
46
                return any(AnyPtr(cast.ToInt32(s))).(K)
47
        case *int64:
48
                return any(AnyPtr(cast.ToInt64(s))).(K)
49
        case uint:
50
                return any(cast.ToUint(s)).(K)
51
        case uint8:
52
                return any(cast.ToUint8(s)).(K)
53
        case uint16:
54
                return any(cast.ToUint16(s)).(K)
55
        case uint32:
56
                return any(cast.ToUint32(s)).(K)
57
        case uint64:
58
                return any(cast.ToUint64(s)).(K)
59
        case *uint:
60
                return any(AnyPtr(cast.ToUint(s))).(K)
61
        case *uint8:
62
                return any(AnyPtr(cast.ToUint8(s))).(K)
63
        case *uint16:
64
                return any(AnyPtr(cast.ToUint16(s))).(K)
65
        case *uint32:
66
                return any(AnyPtr(cast.ToUint32(s))).(K)
67
        case *uint64:
68
                return any(AnyPtr(cast.ToUint64(s))).(K)
69
        case float32:
70
                return any(cast.ToFloat32(s)).(K)
71
        case float64:
72
                return any(cast.ToFloat64(s)).(K)
73
        case *float32:
74
                return any(AnyPtr(cast.ToFloat32(s))).(K)
75
        case *float64:
76
                return any(AnyPtr(cast.ToFloat64(s))).(K)
77
        case string:
78
                return any(cast.ToString(s)).(K)
79
        case *string:
80
                return any(AnyPtr(cast.ToString(s))).(K)
81
        default:
82
                panic(errors.Errorf("cannot mapping %T", d))
83
        }
84
}
func LoopWithInterval
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

71
func LoopWithInterval(ctx context.Context, interval time.Duration,
72
        fn func() bool, opts ...OptionExtender) (err error) {
73
        var (
74
                maxTimes     uint
75
                nextInterval func() time.Duration
76
        )
77
78
        opt := ApplyOptions[loopWithIntervalOption](opts...)
79
        enableJitter := opt.base > 0
80
        enableMaxTimes := opt.maxTimes > 0
81
        if enableJitter {
82
                nextInterval = NextJitterIntervalFunc(opt.base, opt.max, opt.ratio, opt.exp, opt.symmetric)
83
                interval = nextInterval()
84
        }
85
        if enableMaxTimes {
86
                maxTimes = opt.maxTimes
87
        }
88
89
        timer := time.NewTimer(interval)
90
        defer timer.Stop()
91
        for {
92
                if fn() {
93
                        return
94
                }
95
96
                if enableMaxTimes {
97
                        if maxTimes--; maxTimes == 0 {
98
                                return multierr.Append(err, errors.New("exceed the maximum times"))
99
                        }
100
                }
101
102
                // time.Sleep
103
                timer.Reset(interval)
104
                select {
105
                case <-ctx.Done():
106
                        return ctx.Err()
107
                case <-timer.C:
108
                        if enableJitter {
109
                                interval = nextInterval()
110
                        }
111
                }
112
        }
113
}
func Set[T].Equals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

132
func (s *Set[T]) Equals(o *Set[T]) bool {
133
        s.m.RLock()
134
        defer s.m.RUnlock()
135
136
        if s == nil && o == nil {
137
                return true
138
        }
139
        if s == nil || o == nil || s.Size() != o.Size() {
140
                return false
141
        }
142
143
        for item := range s.storage {
144
                if _, ok := o.storage[item]; !ok {
145
                        return false
146
                }
147
        }
148
        for item := range o.storage {
149
                if _, ok := s.storage[item]; !ok {
150
                        return false
151
                }
152
        }
153
154
        return true
155
}
func Set[T].IntersectsWith
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

88
func (s *Set[T]) IntersectsWith(set *Set[T]) bool {
89
        s.m.RLock()
90
        defer s.m.RUnlock()
91
92
        src := set.storage
93
        dst := s.storage
94
        if len(src) > len(dst) {
95
                src, dst = dst, src
96
        }
97
        for val := range src {
98
                if dst == nil {
99
                        return false
100
                }
101
                if _, ok := dst[val]; ok {
102
                        return true
103
                }
104
        }
105
        return false
106
}
func @132:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

132
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
133
                if !value.IsValid() {
134
                        return false, false
135
                }
136
                if value.Type().Kind() == reflect.Struct {
137
                        return false, true
138
                }
139
                tagV := field.Tag.Get(tag)
140
                if pattern.Match([]byte(tagV)) {
141
                        tagValue = tagV
142
                        end = true
143
                        return
144
                }
145
                return
146
        }
func @94:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

94
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
95
                if !value.IsValid() {
96
                        return false, false
97
                }
98
                if value.Type().Kind() == reflect.Struct {
99
                        return false, true
100
                }
101
                tagV := field.Tag.Get(tag)
102
                if tagV == key {
103
                        r = value
104
                        end = true
105
                        return
106
                }
107
                return
108
        }
func @114:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

114
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
115
                if !value.IsValid() {
116
                        return false, false
117
                }
118
                if value.Type().Kind() == reflect.Struct {
119
                        return false, true
120
                }
121
                if keySet.Contains(field.Tag.Get(tag)) {
122
                        r = value
123
                        end = true
124
                        return
125
                }
126
                return
127
        }
func @100:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

100
func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) {
101
                ret := runVariadicFunc(fn, a...)
102
                t1 = ParseVariadicFuncResult[T1](ret, 0)
103
                t2 = ParseVariadicFuncResult[T2](ret, 1)
104
                t3 = ParseVariadicFuncResult[T3](ret, 2)
105
                t4 = ParseVariadicFuncResult[T4](ret, 3)
106
                t5 = ParseVariadicFuncResult[T5](ret, 4)
107
                t6 = ParseVariadicFuncResult[T6](ret, 5)
108
                t7 = ParseVariadicFuncResult[T7](ret, 6)
109
                return
110
        }
func Set[T].IsSubsetOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

70
func (s *Set[T]) IsSubsetOf(set *Set[T]) bool {
71
        s.m.RLock()
72
        defer s.m.RUnlock()
73
74
        for val := range s.storage {
75
                // The empty set is a subset of all sets, but in common business use,
76
                // there is rarely such a mathematical interpretation of the empty set being considered as
77
                // a subset relationship, so false is chosen here.
78
                if set == nil {
79
                        return false
80
                }
81
                if _, ok := set.storage[val]; !ok {
82
                        return false
83
                }
84
        }
85
        return true
86
}
func @87:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

87
func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) {
88
                ret := runVariadicFunc(fn, a...)
89
                t1 = ParseVariadicFuncResult[T1](ret, 0)
90
                t2 = ParseVariadicFuncResult[T2](ret, 1)
91
                t3 = ParseVariadicFuncResult[T3](ret, 2)
92
                t4 = ParseVariadicFuncResult[T4](ret, 3)
93
                t5 = ParseVariadicFuncResult[T5](ret, 4)
94
                t6 = ParseVariadicFuncResult[T6](ret, 5)
95
                return
96
        }
func CryptoRandomLetterAndNumber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

71
func CryptoRandomLetterAndNumber(n int) (string, error) {
72
        b, err := CryptoRandomBytes(n)
73
        if err != nil {
74
                return "", err
75
        }
76
77
        random := make([]byte, 0, n)
78
        for i := 0; i < n; i++ {
79
                random = append(random, randomChars[b[i]%uint8(randomCharsLength)])
80
        }
81
        return string(random), nil
82
}
func CryptoRandomNumbers
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

112
func CryptoRandomNumbers(n int) (string, error) {
113
        b, err := CryptoRandomBytes(n)
114
        if err != nil {
115
                return "", err
116
        }
117
118
        random := make([]byte, 0, n)
119
        for i := 0; i < n; i++ {
120
                random = append(random, randomChars[b[i]%uint8(10)])
121
        }
122
        return string(random), nil
123
}
func @75:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

75
func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) {
76
                ret := runVariadicFunc(fn, a...)
77
                t1 = ParseVariadicFuncResult[T1](ret, 0)
78
                t2 = ParseVariadicFuncResult[T2](ret, 1)
79
                t3 = ParseVariadicFuncResult[T3](ret, 2)
80
                t4 = ParseVariadicFuncResult[T4](ret, 3)
81
                t5 = ParseVariadicFuncResult[T5](ret, 4)
82
                return
83
        }
func JsonStringify[T].UnmarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

30
func (j *JsonStringify[T]) UnmarshalJSON(input []byte) (err error) {
31
        var buf string
32
        if err = json.Unmarshal(input, &buf); err != nil {
33
                return
34
        }
35
        if err = json.Unmarshal(UnsafeStringToBytes(buf), &j.Value); err != nil {
36
                return
37
        }
38
        return
39
}
func JsonStringify[T].MarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

19
func (j *JsonStringify[T]) MarshalJSON() (output []byte, err error) {
20
        var buf []byte
21
        if buf, err = json.Marshal(j.Value); err != nil {
22
                return
23
        }
24
        if output, err = json.Marshal(buf); err != nil {
25
                return
26
        }
27
        return
28
}
func Set[T].Filter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

120
func (s *Set[T]) Filter(fn func(T) bool) *Set[T] {
121
        s.m.Lock()
122
        defer s.m.Unlock()
123
124
        for key := range s.storage {
125
                if !fn(key) {
126
                        delete(s.storage, key)
127
                }
128
        }
129
        return s
130
}
func @64:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

64
func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4) {
65
                ret := runVariadicFunc(fn, a...)
66
                t1 = ParseVariadicFuncResult[T1](ret, 0)
67
                t2 = ParseVariadicFuncResult[T2](ret, 1)
68
                t3 = ParseVariadicFuncResult[T3](ret, 2)
69
                t4 = ParseVariadicFuncResult[T4](ret, 3)
70
                return
71
        }
func Set[T].Reject
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

108
func (s *Set[T]) Reject(fn func(T) bool) *Set[T] {
109
        s.m.Lock()
110
        defer s.m.Unlock()
111
112
        for key := range s.storage {
113
                if fn(key) {
114
                        delete(s.storage, key)
115
                }
116
        }
117
        return s
118
}
func InvalidUnmarshalError.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

59
func (e *InvalidUnmarshalError) Error() string {
60
        if e.Type == nil {
61
                return "common/utils: Unmarshal(nil)"
62
        }
63
64
        if e.Type.Kind() != reflect.Pointer {
65
                return "common/utils: Unmarshal(non-pointer " + e.Type.String() + ")"
66
        }
67
        return "common/utils: Unmarshal(nil " + e.Type.String() + ")"
68
}
func @54:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

54
func(o *loopWithIntervalOption) {
55
                o.base = base
56
                o.max = max
57
                o.ratio = ratio
58
                o.exp = exp
59
                o.symmetric = symmetric
60
        }
func Heap[E].Copy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

50
func (h *Heap[E]) Copy() *Heap[E] {
51
        ret := &_heap[E]{cmp: h.data.cmp}
52
        ret.d = make([]E, len(h.data.d))
53
        copy(ret.d, h.data.d)
54
        heap.Init(ret)
55
        return &Heap[E]{data: ret}
56
}
func RandomNumbers
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

103
func RandomNumbers(n int) string {
104
        rand.Seed(time.Now().UnixNano())
105
        ret := ""
106
        for i := 0; i < n; i++ {
107
                ret += strconv.Itoa(rand.Intn(10))
108
        }
109
        return ret
110
}
func @54:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

54
func(a ...any) (t1 T1, t2 T2, t3 T3) {
55
                ret := runVariadicFunc(fn, a...)
56
                t1 = ParseVariadicFuncResult[T1](ret, 0)
57
                t2 = ParseVariadicFuncResult[T2](ret, 1)
58
                t3 = ParseVariadicFuncResult[T3](ret, 2)
59
                return
60
        }
func @23:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

23
func(a ...any) (b []any) {
24
                ret := runVariadicFunc(fn, a...)
25
                b = make([]any, 0, len(b))
26
                for i := 0; i < len(ret); i++ {
27
                        b = append(b, ret[i].Interface())
28
                }
29
                return
30
        }
func MapSliceToMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/map.go:

51
func MapSliceToMap[T comparable, K any](s []map[T]K) (d map[T]K) {
52
        d = make(map[T]K, len(s))
53
        for _, kv := range s {
54
                for k, v := range kv {
55
                        d[k] = v
56
                }
57
        }
58
        return
59
}
func DecimalPlaces
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

9
func DecimalPlaces(num float64) int {
10
        str := strconv.FormatFloat(num, 'f', -1, 64)
11
        if i := strings.LastIndex(str, "."); i >= 0 {
12
                return len(str[i+1:])
13
        }
14
        return 0
15
}
func CryptoRandomBytes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

63
func CryptoRandomBytes(size int) ([]byte, error) {
64
        b := make([]byte, size)
65
        if _, err := cryptoRand.Read(b); err != nil {
66
                return nil, err
67
        }
68
        return b, nil
69
}
func UUID20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

42
func UUID20() string {
43
        id := uuid.New()
44
        t := make([]byte, ascii85.MaxEncodedLen(len(id)))
45
        n := ascii85.Encode(t, id[:])
46
        return string(t[:n])
47
}
func SliceRemove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/slice.go:

3
func SliceRemove[T any, TS ~[]T](s TS, filter func(t T) bool) (d TS) {
4
        for i, item := range s {
5
                if filter(item) {
6
                        s = append(s[i:], s[i+1:]...)
7
                }
8
        }
9
        return s
10
}
func GetFieldByTagWithKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

112
func GetFieldByTagWithKeys(data any, tag string, keys []string) (r reflect.Value, e error) {
113
        keySet := NewSet[string](keys...)
114
        TraverseValue(data, true, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
115
                if !value.IsValid() {
116
                        return false, false
117
                }
118
                if value.Type().Kind() == reflect.Struct {
119
                        return false, true
120
                }
121
                if keySet.Contains(field.Tag.Get(tag)) {
122
                        r = value
123
                        end = true
124
                        return
125
                }
126
                return
127
        })
128
        return
129
}
func NewHeap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

59
func NewHeap[E any](t []E, cmp func(e1, e2 E) int) *Heap[E] {
60
        ret := &_heap[E]{d: t, cmp: cmp}
61
        heap.Init(ret)
62
        return &Heap[E]{data: ret}
63
}
func Set[T].Size
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

23
func (s *Set[T]) Size() int {
24
        s.m.RLock()
25
        defer s.m.RUnlock()
26
        return len(s.storage)
27
}
func Set[T].Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sets.go:

157
func (s *Set[T]) Clone() (r *Set[T]) {
158
        s.m.RLock()
159
        defer s.m.RUnlock()
160
        return NewSet(s.Items()...)
161
}
func Heap[E].Element
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

37
func (h *Heap[E]) Element(index int) (e E, err error) {
38
        if index < 0 || index >= h.data.Len() {
39
                return e, ErrOutOfRange
40
        }
41
        return h.data.d[index], nil
42
}
func IsInRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compare.go:

43
func IsInRange[T constraint.Sortable](num, min, max T) bool {
44
        if num < min || num > max {
45
                return false
46
        }
47
        return true
48
}
func MustOk
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/candy.go:

78
func MustOk[T any](out T, ok bool) T {
79
        if !ok {
80
                panic(errors.Errorf("get %T with ok is false", out))
81
        }
82
        return out
83
}
func UUID22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

49
func UUID22() string {
50
        id := uuid.New()
51
        return base64.RawURLEncoding.EncodeToString(id[:])
52
}
func GetFieldTagValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

131
func GetFieldTagValue(data any, tag string, pattern *regexp.Regexp) (tagValue string, e error) {
132
        TraverseValue(data, true, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
133
                if !value.IsValid() {
134
                        return false, false
135
                }
136
                if value.Type().Kind() == reflect.Struct {
137
                        return false, true
138
                }
139
                tagV := field.Tag.Get(tag)
140
                if pattern.Match([]byte(tagV)) {
141
                        tagValue = tagV
142
                        end = true
143
                        return
144
                }
145
                return
146
        })
147
        return
148
}
func IntNarrow
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

17
func IntNarrow(num int) (result any) {
18
        IfAny(
19
                func() bool { result = int8(num); return IsInRange(num, math.MinInt8, math.MaxInt8) },
20
                func() bool { result = int16(num); return IsInRange(num, math.MinInt16, math.MaxInt16) },
21
                func() bool { result = int32(num); return IsInRange(num, math.MinInt32, math.MaxInt32) },
22
                func() bool { result = int64(num); return IsInRange(num, math.MinInt64, math.MaxInt64) },
23
        )
24
        return
25
}
func GetFieldByTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/reflect.go:

93
func GetFieldByTag(data any, tag, key string) (r reflect.Value, e error) {
94
        TraverseValue(data, true, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
95
                if !value.IsValid() {
96
                        return false, false
97
                }
98
                if value.Type().Kind() == reflect.Struct {
99
                        return false, true
100
                }
101
                tagV := field.Tag.Get(tag)
102
                if tagV == key {
103
                        r = value
104
                        end = true
105
                        return
106
                }
107
                return
108
        })
109
        return
110
}
func @19:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

19
func() bool { result = int8(num); return IsInRange(num, math.MinInt8, math.MaxInt8) }
func @20:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

20
func() bool { result = int16(num); return IsInRange(num, math.MinInt16, math.MaxInt16) }
func @181:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

181
func() bool {
182
                        _, err = Catch(func() { inspect.SetField(source, "s", rand.NewSource(seed)) })
183
                        return err == nil
184
                }
func @21:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

21
func() bool { result = int32(num); return IsInRange(num, math.MinInt32, math.MaxInt32) }
func @22:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

22
func() bool { result = int64(num); return IsInRange(num, math.MinInt64, math.MaxInt64) }
func @29:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

29
func() bool { result = uint8(num); return IsInRange(num, 0, math.MaxUint8) }
func IsValidTimestamp
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

38
func IsValidTimestamp(timeMS int64) bool {
39
        year := GetTime(timeMS).Year()
40
        return year >= minYear && year < maxYear
41
}
func @30:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

30
func() bool { result = uint16(num); return IsInRange(num, 0, math.MaxUint16) }
func @31:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

31
func() bool { result = uint32(num); return IsInRange(num, 0, math.MaxUint32) }
func _heap[E].Pop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

21
func (h *_heap[E]) Pop() (x any)       { x, h.d = h.d[len(h.d)-1], h.d[0:len(h.d)-1]; return x }
func Sort
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sort.go:

5
func Sort[E any](data []E, cmp func(e1, e2 E) int) {
6
        sortObj := sortable[E]{data: data, cmp: cmp}
7
        sort.Sort(sortObj)
8
}
func SortStable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sort.go:

10
func SortStable[E any](data []E, cmp func(e1, e2 E) int) {
11
        sortObj := sortable[E]{data: data, cmp: cmp}
12
        sort.Stable(sortObj)
13
}
func _heap[E].Push
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

20
func (h *_heap[E]) Push(x any)         { v := append(h.d, x.(E)); h.d = v }
func _heap[E].Less
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

18
func (h *_heap[E]) Less(i, j int) bool { v := h.cmp(h.d[i], h.d[j]); return v < 0 }
func @32:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

32
func() bool { result = uint64(num); return IsInRange(num, 0, math.MaxUint64) }
func UintNarrow
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/number.go:

27
func UintNarrow(num uint) (result any) {
28
        IfAny(
29
                func() bool { result = uint8(num); return IsInRange(num, 0, math.MaxUint8) },
30
                func() bool { result = uint16(num); return IsInRange(num, 0, math.MaxUint16) },
31
                func() bool { result = uint32(num); return IsInRange(num, 0, math.MaxUint32) },
32
                func() bool { result = uint64(num); return IsInRange(num, 0, math.MaxUint64) },
33
        )
34
        return
35
}
func UnsafeBytesToString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

160
func UnsafeBytesToString(b []byte) string {
161
        return *(*string)(unsafe.Pointer(&b))
162
}
func IsStrPtrBlank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/string.go:

15
func IsStrPtrBlank(s *string) bool {
16
        return s == nil || IsStrBlank(*s)
17
}
func UnsafeStringToBytes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/conv.go:

149
func UnsafeStringToBytes(s string) []byte {
150
        return *(*[]byte)(unsafe.Pointer(
151
                &struct {
152
                        string
153
                        Cap int
154
                }{s, len(s)},
155
        ))
156
}
func WrapFunc7
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

99
func WrapFunc7[T1, T2, T3, T4, T5, T6, T7 any](fn any) func(...any) (T1, T2, T3, T4, T5, T6, T7) {
100
        return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) {
101
                ret := runVariadicFunc(fn, a...)
102
                t1 = ParseVariadicFuncResult[T1](ret, 0)
103
                t2 = ParseVariadicFuncResult[T2](ret, 1)
104
                t3 = ParseVariadicFuncResult[T3](ret, 2)
105
                t4 = ParseVariadicFuncResult[T4](ret, 3)
106
                t5 = ParseVariadicFuncResult[T5](ret, 4)
107
                t6 = ParseVariadicFuncResult[T6](ret, 5)
108
                t7 = ParseVariadicFuncResult[T7](ret, 6)
109
                return
110
        }
111
}
func UUID_
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

28
func UUID_() string {
29
        return strings.Replace(uuid.New().String(), constant.Hyphen, "", -1)
30
}
func sortable[E].Less
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sort.go:

22
func (s sortable[E]) Less(i, j int) bool { return s.cmp(s.data[i], s.data[j]) < 0 }
func sortable[E].Swap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sort.go:

21
func (s sortable[E]) Swap(i, j int)      { s.data[i], s.data[j] = s.data[j], s.data[i] }
func _heap[E].Swap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

19
func (h *_heap[E]) Swap(i, j int)      { h.d[i], h.d[j] = h.d[j], h.d[i] }
func sortable[E].Len
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/sort.go:

20
func (s sortable[E]) Len() int           { return len(s.data) }
func @26:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

26
func(e *enumStringOption) {
27
                e.ignoreCaseSensitivity = true
28
        }
func Heap[E].Push
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

30
func (h *Heap[E]) Push(v E) { heap.Push(h.data, v) }
func ParseTagOverwrite
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

19
func ParseTagOverwrite(overwrite bool) OptionFunc[parseTagOption] {
20
        return func(o *parseTagOption) {
21
                o.overwrite = overwrite
22
        }
23
}
func @20:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/tag.go:

20
func(o *parseTagOption) {
21
                o.overwrite = overwrite
22
        }
func Heap[E].Pop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

35
func (h *Heap[E]) Pop() E { return heap.Pop(h.data).(E) }
func Heap[E].Remove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

46
func (h *Heap[E]) Remove(index int) E { return heap.Remove(h.data, index).(E) }
func Heap[E].Len
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

47
func (h *Heap[E]) Len() int           { return len(h.data.d) }
func WrapFuncAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

22
func WrapFuncAny(fn any) func(...any) []any {
23
        return func(a ...any) (b []any) {
24
                ret := runVariadicFunc(fn, a...)
25
                b = make([]any, 0, len(b))
26
                for i := 0; i < len(ret); i++ {
27
                        b = append(b, ret[i].Interface())
28
                }
29
                return
30
        }
31
}
func GetTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

25
func GetTime(timestampMs int64) time.Time {
26
        return time.UnixMilli(timestampMs)
27
}
func IgnoreEnumStringCase
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/enum.go:

25
func IgnoreEnumStringCase() enumStringOptFn {
26
        return func(e *enumStringOption) {
27
                e.ignoreCaseSensitivity = true
28
        }
29
}
func WrapFunc6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

86
func WrapFunc6[T1, T2, T3, T4, T5, T6 any](fn any) func(...any) (T1, T2, T3, T4, T5, T6) {
87
        return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) {
88
                ret := runVariadicFunc(fn, a...)
89
                t1 = ParseVariadicFuncResult[T1](ret, 0)
90
                t2 = ParseVariadicFuncResult[T2](ret, 1)
91
                t3 = ParseVariadicFuncResult[T3](ret, 2)
92
                t4 = ParseVariadicFuncResult[T4](ret, 3)
93
                t5 = ParseVariadicFuncResult[T5](ret, 4)
94
                t6 = ParseVariadicFuncResult[T6](ret, 5)
95
                return
96
        }
97
}
func LoopJitterInterval
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

52
func LoopJitterInterval(base, max time.Duration, ratio, exp float64,
53
        symmetric bool) OptionFunc[loopWithIntervalOption] {
54
        return func(o *loopWithIntervalOption) {
55
                o.base = base
56
                o.max = max
57
                o.ratio = ratio
58
                o.exp = exp
59
                o.symmetric = symmetric
60
        }
61
}
func WrapFunc5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

74
func WrapFunc5[T1, T2, T3, T4, T5 any](fn any) func(...any) (T1, T2, T3, T4, T5) {
75
        return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) {
76
                ret := runVariadicFunc(fn, a...)
77
                t1 = ParseVariadicFuncResult[T1](ret, 0)
78
                t2 = ParseVariadicFuncResult[T2](ret, 1)
79
                t3 = ParseVariadicFuncResult[T3](ret, 2)
80
                t4 = ParseVariadicFuncResult[T4](ret, 3)
81
                t5 = ParseVariadicFuncResult[T5](ret, 4)
82
                return
83
        }
84
}
func LoopMaxTimes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

64
func LoopMaxTimes(maxTimes uint) OptionFunc[loopWithIntervalOption] {
65
        return func(o *loopWithIntervalOption) {
66
                o.maxTimes = maxTimes
67
        }
68
}
func @65:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/time.go:

65
func(o *loopWithIntervalOption) {
66
                o.maxTimes = maxTimes
67
        }
func NewSafeRand
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

165
func NewSafeRand(seed int64) *rand.Rand {
166
        return rand.New(newBuiltinLockedSource(seed))
167
}
func WrapFunc4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

63
func WrapFunc4[T1, T2, T3, T4 any](fn any) func(...any) (T1, T2, T3, T4) {
64
        return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4) {
65
                ret := runVariadicFunc(fn, a...)
66
                t1 = ParseVariadicFuncResult[T1](ret, 0)
67
                t2 = ParseVariadicFuncResult[T2](ret, 1)
68
                t3 = ParseVariadicFuncResult[T3](ret, 2)
69
                t4 = ParseVariadicFuncResult[T4](ret, 3)
70
                return
71
        }
72
}
func @182:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/random.go:

182
func() { inspect.SetField(source, "s", rand.NewSource(seed)) }
func WrapFunc3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/func.go:

53
func WrapFunc3[T1, T2, T3 any](fn any) func(...any) (T1, T2, T3) {
54
        return func(a ...any) (t1 T1, t2 T2, t3 T3) {
55
                ret := runVariadicFunc(fn, a...)
56
                t1 = ParseVariadicFuncResult[T1](ret, 0)
57
                t2 = ParseVariadicFuncResult[T2](ret, 1)
58
                t3 = ParseVariadicFuncResult[T3](ret, 2)
59
                return
60
        }
61
}
func Error.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/error.go:

5
func (e Error) Error() string {
6
        return string(e)
7
}
func MustJsonMarshalString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/marshal.go:

42
func MustJsonMarshalString(s any) string       { return string(MustJsonMarshal(s)) }
func _heap[E].Len
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/heap.go:

17
func (h *_heap[E]) Len() int           { return len(h.d) }
Package Overview: github.com/wfusion/gofusion/common/utils/cipher 85.6%

Please select a function to see what's left for testing.

newBlockModeWrapper(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 7/7
@36:8(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 6/6
EncryptStreamFunc(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 6/6
@40:8(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 100.0% 6/6
enc.Flush(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 4/4
dec.Close(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 100.0% 4/4
@159:8(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 3/3
@28:9(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 3/3
@233:8(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 3/3
@19:9(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 3/3
@162:8(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 100.0% 3/3
wrapErr(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 2/2
newAbstractAEADWrapper(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 2/2
@54:8(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 2/2
enc.Close(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 2/2
@36:9(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 2/2
@43:9(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 2/2
Mode.NeedIV(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 100.0% 1/1
wrapStream(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
blockModeWrapper.CipherMode(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
blockModeWrapper.PlainBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
wrapBlockMode(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
@74:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@59:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@54:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@49:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@35:23(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 100.0% 1/1
blockModeWrapper.CipherBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
@44:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@39:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@35:18(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
wrapBlock(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 100.0% 1/1
@165:9(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 100.0% 1/1
Mode.IsValid(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 100.0% 1/1
@79:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@34:18(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
Algorithm.String(...) github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go 100.0% 1/1
@89:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@31:23(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 1/1
newAEADDecryptWrapper(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 1/1
@33:18(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@94:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
@32:18(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
Algorithm.IsValid(...) github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go 100.0% 1/1
newAEADEncryptWrapper(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 1/1
@162:9(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 100.0% 1/1
rc4Wrapper.CipherBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go 100.0% 1/1
rc4Wrapper.PlainBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go 100.0% 1/1
abstractAEADWrapper.CipherMode(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 1/1
abstractAEADWrapper.CipherBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 1/1
abstractAEADWrapper.PlainBlockSize(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 100.0% 1/1
rc4Wrapper.CipherMode(...) github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go 100.0% 1/1
Mode.String(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 100.0% 1/1
Mode.SupportStream(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 100.0% 1/1
Mode.ShouldPadding(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 100.0% 1/1
@84:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 100.0% 1/1
encrypt(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 92.6% 25/27
decrypt(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 92.3% 24/26
NewEncFunc(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 92.3% 12/13
dec.Read(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 89.7% 35/39
enc.Write(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 89.5% 17/19
NewDecFunc(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 84.6% 11/13
@19:9(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 83.3% 5/6
DecryptStreamFunc(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 83.3% 5/6
EncryptBytesFunc(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 83.3% 5/6
blockModeWrapper.CryptBlocks(...) github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go 81.8% 9/11
aeadEncryptWrapper.CryptBlocks(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 81.8% 9/11
@126:31(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@136:17(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@118:30(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@144:30(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@110:17(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
DecryptBytesFunc(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 80.0% 4/5
rc4Wrapper.CryptBlocks(...) github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go 80.0% 4/5
@152:31(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@99:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
@64:12(...) github.com/wfusion/gofusion/common/utils/cipher/types.go 80.0% 4/5
aeadDecryptWrapper.CryptBlocks(...) github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go 76.9% 10/13
PKCS7Pad(...) github.com/wfusion/gofusion/common/utils/cipher/padding.go 75.0% 3/4
getEncrypter(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 70.0% 14/20
getDecrypter(...) github.com/wfusion/gofusion/common/utils/cipher/decrypt.go 70.0% 14/20
enc.flush(...) github.com/wfusion/gofusion/common/utils/cipher/encrypt.go 70.0% 7/10
PKCS7Unpad(...) github.com/wfusion/gofusion/common/utils/cipher/padding.go 70.0% 7/10
ParseMode(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 50.0% 3/6
ParseAlgorithm(...) github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go 50.0% 3/6
Algorithm.Value(...) github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go 0.0% 0/1
Mode.Value(...) github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go 0.0% 0/1
func newBlockModeWrapper
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

49
func newBlockModeWrapper(opts ...utils.OptionExtender) (w *blockModeWrapper) {
50
        opt := utils.ApplyOptions[blockModeOption](opts...)
51
        w = &blockModeWrapper{
52
                block:     opt.block,
53
                blockMode: opt.blockMode,
54
                stream:    opt.stream,
55
                blockSize: 0,
56
                mode:      opt.mode,
57
                isEncoder: opt.isEncoder,
58
        }
59
60
        switch {
61
        case opt.block != nil:
62
                w.blockSize = w.block.BlockSize()
63
        case opt.blockMode != nil:
64
                w.blockSize = w.blockMode.BlockSize()
65
        case opt.stream != nil:
66
                w.blockSize = defaultBlockSize * blockSizeTimes
67
        }
68
69
        return
70
}
func @36:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

36
func(dst io.Writer, src io.Reader) (err error) {
37
                buf, cb := utils.BytesPool.Get(defaultBlockSize * blockSizeTimes)
38
                defer cb()
39
40
                wrapper := fn(dst)
41
                defer utils.CloseAnyway(wrapper)
42
43
                _, err = io.CopyBuffer(wrapper, src, buf)
44
                return
45
        }
func EncryptStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

27
func EncryptStreamFunc(algo Algorithm, mode Mode, key, iv []byte) (
28
        enc func(dst io.Writer, src io.Reader) (err error), err error) {
29
        var fn func(w io.Writer) io.WriteCloser
30
31
        _, err = utils.Catch(func() { fn = NewEncFunc(algo, mode, key, iv) })
32
        if err != nil {
33
                return nil, err
34
        }
35
36
        enc = func(dst io.Writer, src io.Reader) (err error) {
37
                buf, cb := utils.BytesPool.Get(defaultBlockSize * blockSizeTimes)
38
                defer cb()
39
40
                wrapper := fn(dst)
41
                defer utils.CloseAnyway(wrapper)
42
43
                _, err = io.CopyBuffer(wrapper, src, buf)
44
                return
45
        }
46
47
        return
48
}
func @40:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

40
func(dst io.Writer, src io.Reader) (err error) {
41
                buf, cb := utils.BytesPool.Get(defaultBlockSize * blockSizeTimes)
42
                defer cb()
43
44
                wrapper := fn(src)
45
                defer utils.CloseAnyway(wrapper)
46
                _, err = io.CopyBuffer(dst, wrapper, buf)
47
                return
48
        }
func enc.Flush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

224
func (e *enc) Flush() (err error) {
225
        defer utils.FlushAnyway(e.w)
226
        if e.n > 0 {
227
                err = e.flush()
228
        }
229
        return
230
}
func dec.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

246
func (d *dec) Close() (err error) {
247
        utils.CloseAnyway(d.r)
248
        if d.cb != nil {
249
                d.cb()
250
        }
251
        return
252
}
func @159:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

159
func() { bcb(); scb(); sbcb() }
func @28:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

28
func(o *blockModeOption) {
29
                o.mode = mode
30
                o.block = block
31
                o.isEncoder = isEncoder
32
        }
func @233:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

233
func() {
234
                utils.CloseAnyway(e.w)
235
                if e.cb != nil {
236
                        e.cb()
237
                }
238
        }
func @19:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

19
func(src []byte) (dst []byte, err error) {
20
                if mode.ShouldPadding() {
21
                        src = PKCS7Pad(src, plainBlockSize)
22
                }
23
                return encrypt(bm, src)
24
        }
func @162:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

162
func() { bcb(); ucb(); ubcb() }
func wrapErr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

163
func wrapErr[T any](a T) (b T, err error) { b = a; return }
func newAbstractAEADWrapper
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

27
func newAbstractAEADWrapper(cipherAEAD cipher.AEAD, blockSize int, mode Mode) abstractAEADWrapper {
28
        plainBlockSize := blockSize * blockSizeTimes
29
        return abstractAEADWrapper{
30
                AEAD:            cipherAEAD,
31
                overheadSize:    cipherAEAD.Overhead(),
32
                nonceSize:       cipherAEAD.NonceSize(),
33
                blockSize:       blockSize,
34
                plainBlockSize:  plainBlockSize,
35
                cipherBlockSize: cipherAEAD.NonceSize() + cipherAEAD.Overhead() + plainBlockSize,
36
                sealedSize:      cipherAEAD.Overhead() + plainBlockSize,
37
                mode:            mode,
38
        }
39
}
func @54:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

54
func() {
55
                for _, cb := range defers {
56
                        cb()
57
                }
58
        }
func enc.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

232
func (e *enc) Close() (err error) {
233
        defer func() {
234
                utils.CloseAnyway(e.w)
235
                if e.cb != nil {
236
                        e.cb()
237
                }
238
        }()
239
240
        return e.Flush()
241
}
func @36:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

36
func(o *blockModeOption) {
37
                o.mode = mode
38
                o.blockMode = bm
39
        }
func @43:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

43
func(o *blockModeOption) {
44
                o.mode = mode
45
                o.stream = stream
46
        }
func Mode.NeedIV
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

57
func (m Mode) NeedIV() bool {
58
        return ivMode.Contains(m)
59
}
func wrapStream
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

42
func wrapStream(stream cipher.Stream, mode Mode) utils.OptionFunc[blockModeOption] {
43
        return func(o *blockModeOption) {
44
                o.mode = mode
45
                o.stream = stream
46
        }
47
}
func blockModeWrapper.CipherMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

72
func (b *blockModeWrapper) CipherMode() Mode     { return b.mode }
func blockModeWrapper.PlainBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

73
func (b *blockModeWrapper) PlainBlockSize() int  { return b.blockSize }
func wrapBlockMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

35
func wrapBlockMode(bm cipher.BlockMode, mode Mode) utils.OptionFunc[blockModeOption] {
36
        return func(o *blockModeOption) {
37
                o.mode = mode
38
                o.blockMode = bm
39
        }
40
}
func @74:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

74
func(b cipher.Block, iv []byte) (e blockMode, err error) {
75
                        return wrapErr(newBlockModeWrapper(
76
                                wrapBlock(b, ModeECB, false)),
77
                        )
78
                }
func @59:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

59
func(b cipher.Block, iv []byte) (e blockMode, err error) {
60
                        return wrapErr(newBlockModeWrapper(
61
                                wrapStream(cipher.NewOFB(b, iv), ModeOFB)),
62
                        )
63
                }
func @54:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

54
func(b cipher.Block, iv []byte) (e blockMode, err error) {
55
                        return wrapErr(newBlockModeWrapper(
56
                                wrapStream(cipher.NewCTR(b, iv), ModeCTR)),
57
                        )
58
                }
func @49:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

49
func(b cipher.Block, iv []byte) (e blockMode, err error) {
50
                        return wrapErr(newBlockModeWrapper(
51
                                wrapStream(cipher.NewCFBEncrypter(b, iv), ModeCFB)),
52
                        )
53
                }
func @35:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

35
func() { fn = NewDecFunc(algo, mode, key, iv) }
func blockModeWrapper.CipherBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

74
func (b *blockModeWrapper) CipherBlockSize() int { return b.blockSize }
func @44:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

44
func(b cipher.Block, iv []byte) (e blockMode, err error) {
45
                        return wrapErr(newBlockModeWrapper(
46
                                wrapBlockMode(cipher.NewCBCEncrypter(b, iv), ModeCBC)),
47
                        )
48
                }
func @39:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

39
func(b cipher.Block, iv []byte) (e blockMode, err error) {
40
                        return wrapErr(newBlockModeWrapper(
41
                                wrapBlock(b, ModeECB, true)),
42
                        )
43
                }
func @35:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

35
func(key []byte) (cipher.Block, error) { return sm4.NewCipher(key) }
func wrapBlock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

27
func wrapBlock(block cipher.Block, mode Mode, isEncoder bool) utils.OptionFunc[blockModeOption] {
28
        return func(o *blockModeOption) {
29
                o.mode = mode
30
                o.block = block
31
                o.isEncoder = isEncoder
32
        }
33
}
func @165:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

165
func(r io.Reader) io.ReadCloser {
166
                return &dec{
167
                        bm:        bm,
168
                        r:         r,
169
                        buf:       buf,
170
                        cb:        cb,
171
                        n:         0,
172
                        end:       0,
173
                        size:      size,
174
                        eof:       false,
175
                        unsealed:  unsealed,
176
                        unsealBuf: unsealBuf,
177
                }
178
        }
func Mode.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

49
func (m Mode) IsValid() bool {
50
        return modeEnum.IsValid(m)
51
}
func @79:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

79
func(b cipher.Block, iv []byte) (bm blockMode, err error) {
80
                        return wrapErr(newBlockModeWrapper(
81
                                wrapBlockMode(cipher.NewCBCDecrypter(b, iv), ModeCBC)),
82
                        )
83
                }
func @34:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

34
func(key []byte) (cipher.Block, error) { return aes.NewCipher(key) }
func Algorithm.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go:

41
func (e Algorithm) String() string {
42
        return algorithmEnum.String(e)
43
}
func @89:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

89
func(b cipher.Block, iv []byte) (bm blockMode, err error) {
90
                        return wrapErr(newBlockModeWrapper(
91
                                wrapStream(cipher.NewCTR(b, iv), ModeCTR)),
92
                        )
93
                }
func @31:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

31
func() { fn = NewEncFunc(algo, mode, key, iv) }
func newAEADDecryptWrapper
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

75
func newAEADDecryptWrapper(cipherAEAD cipher.AEAD, blockSize int, mode Mode) blockMode {
76
        return &aeadDecryptWrapper{abstractAEADWrapper: newAbstractAEADWrapper(cipherAEAD, blockSize, mode)}
77
}
func @33:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

33
func(key []byte) (cipher.Block, error) { return des.NewTripleDESCipher(key) }
func @94:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

94
func(b cipher.Block, iv []byte) (bm blockMode, err error) {
95
                        return wrapErr(newBlockModeWrapper(
96
                                wrapStream(cipher.NewOFB(b, iv), ModeOFB)),
97
                        )
98
                }
func @32:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

32
func(key []byte) (cipher.Block, error) { return des.NewCipher(key) }
func Algorithm.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go:

45
func (e Algorithm) IsValid() bool {
46
        return algorithmEnum.IsValid(e)
47
}
func newAEADEncryptWrapper
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

49
func newAEADEncryptWrapper(cipherAEAD cipher.AEAD, blockSize int, mode Mode) blockMode {
50
        return &aeadEncryptWrapper{abstractAEADWrapper: newAbstractAEADWrapper(cipherAEAD, blockSize, mode)}
51
}
func @162:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

162
func(w io.Writer) io.WriteCloser {
163
                return &enc{
164
                        bm:      bm,
165
                        w:       w,
166
                        n:       0,
167
                        buf:     buf,
168
                        cb:      cb,
169
                        sealed:  sealed,
170
                        sealBuf: sealBuf,
171
                }
172
        }
func rc4Wrapper.CipherBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go:

11
func (r *rc4Wrapper) CipherBlockSize() int { return 0 }
func rc4Wrapper.PlainBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go:

10
func (r *rc4Wrapper) PlainBlockSize() int  { return 0 }
func abstractAEADWrapper.CipherMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

43
func (a *abstractAEADWrapper) CipherMode() Mode     { return a.mode }
func abstractAEADWrapper.CipherBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

42
func (a *abstractAEADWrapper) CipherBlockSize() int { return a.cipherBlockSize }
func abstractAEADWrapper.PlainBlockSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

41
func (a *abstractAEADWrapper) PlainBlockSize() int  { return a.plainBlockSize }
func rc4Wrapper.CipherMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go:

9
func (r *rc4Wrapper) CipherMode() Mode     { return modeStream }
func Mode.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

45
func (m Mode) String() string {
46
        return modeEnum.String(m)
47
}
func Mode.SupportStream
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

61
func (m Mode) SupportStream() bool {
62
        return streamMode.Contains(m)
63
}
func Mode.ShouldPadding
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

53
func (m Mode) ShouldPadding() bool {
54
        return paddingMode.Contains(m)
55
}
func @84:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

84
func(b cipher.Block, iv []byte) (bm blockMode, err error) {
85
                        return wrapErr(newBlockModeWrapper(
86
                                wrapStream(cipher.NewCFBDecrypter(b, iv), ModeCFB)),
87
                        )
88
                }
func encrypt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

50
func encrypt(bm blockMode, src []byte) (dst []byte, err error) {
51
        plainBlockSize := bm.PlainBlockSize()
52
        cipherBlockSize := bm.CipherBlockSize()
53
        defers := make([]func(), 0, 3)
54
        defer func() {
55
                for _, cb := range defers {
56
                        cb()
57
                }
58
        }()
59
60
        w, cb := utils.BytesBufferPool.Get(nil)
61
        defers = append(defers, cb)
62
63
        if plainBlockSize != 0 && cipherBlockSize != 0 {
64
                w.Grow((len(src) / plainBlockSize) * cipherBlockSize)
65
        } else {
66
                plainBlockSize, cipherBlockSize = len(src), len(src)
67
                w.Grow(cipherBlockSize)
68
        }
69
70
        sealed, cb := utils.BytesPool.Get(cipherBlockSize)
71
        defers = append(defers, cb)
72
73
        buf, cb := utils.BytesPool.Get(plainBlockSize)
74
        defers = append(defers, cb)
75
76
        var n, blockSize int
77
        for len(src) > 0 {
78
                blockSize = utils.Min(plainBlockSize, len(src))
79
                n, err = bm.CryptBlocks(sealed[:cipherBlockSize], src[:blockSize], buf)
80
                if err != nil {
81
                        return
82
                }
83
                if _, err = w.Write(sealed[:n]); err != nil {
84
                        return
85
                }
86
                src = src[blockSize:]
87
        }
88
89
        bs := w.Bytes()
90
        dst = make([]byte, len(bs))
91
        copy(dst, bs)
92
        return
93
}
func decrypt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

53
func decrypt(bm blockMode, src []byte) (dst []byte, err error) {
54
        plainBlockSize := bm.PlainBlockSize()
55
        cipherBlockSize := bm.CipherBlockSize()
56
        defers := make([]func(), 0, 3)
57
58
        w, cb := utils.BytesBufferPool.Get(nil)
59
        defers = append(defers, cb)
60
61
        if plainBlockSize != 0 && cipherBlockSize != 0 {
62
                w.Grow((len(src) / cipherBlockSize) * plainBlockSize)
63
        } else {
64
                plainBlockSize, cipherBlockSize = len(src), len(src)
65
                w.Grow(plainBlockSize)
66
        }
67
68
        unsealed, cb := utils.BytesPool.Get(plainBlockSize)
69
        defers = append(defers, cb)
70
71
        buf, cb := utils.BytesPool.Get(plainBlockSize)
72
        defers = append(defers, cb)
73
74
        var n, blockSize int
75
        for len(src) > 0 {
76
                blockSize = utils.Min(cipherBlockSize, len(src))
77
                n, err = bm.CryptBlocks(unsealed[:plainBlockSize], src[:blockSize], buf)
78
                if err != nil {
79
                        return
80
                }
81
                if _, err = w.Write(unsealed[:n]); err != nil {
82
                        return
83
                }
84
                src = src[blockSize:]
85
        }
86
87
        bs := w.Bytes()
88
        dst = make([]byte, len(bs))
89
        copy(dst, bs)
90
        return
91
}
func NewEncFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

141
func NewEncFunc(algo Algorithm, mode Mode, key, iv []byte) func(w io.Writer) io.WriteCloser {
142
        bm, err := getEncrypter(algo, mode, key, iv)
143
        if err != nil {
144
                panic(err)
145
        }
146
        if !bm.CipherMode().SupportStream() {
147
                panic(ErrNotSupportStream)
148
        }
149
150
        var (
151
                buf, sealed, sealBuf []byte
152
                cb                   func()
153
        )
154
        if bm.PlainBlockSize() > 0 {
155
                var bcb, scb, sbcb func()
156
                buf, bcb = utils.BytesPool.Get(bm.PlainBlockSize())
157
                sealed, scb = utils.BytesPool.Get(bm.CipherBlockSize())
158
                sealBuf, sbcb = utils.BytesPool.Get(bm.PlainBlockSize())
159
                cb = func() { bcb(); scb(); sbcb() }
160
        }
161
162
        return func(w io.Writer) io.WriteCloser {
163
                return &enc{
164
                        bm:      bm,
165
                        w:       w,
166
                        n:       0,
167
                        buf:     buf,
168
                        cb:      cb,
169
                        sealed:  sealed,
170
                        sealBuf: sealBuf,
171
                }
172
        }
173
}
func dec.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

181
func (d *dec) Read(p []byte) (n int, err error) {
182
        var (
183
                nr, nc int
184
                dst    []byte
185
        )
186
187
        if d.buf == nil {
188
                n, err = d.r.Read(p)
189
                d.eof = errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF)
190
                if err != nil && !d.eof {
191
                        return
192
                }
193
                dst, err = decrypt(d.bm, p[:n])
194
                if err != nil {
195
                        return
196
                }
197
                n = copy(p[:len(dst)], dst)
198
                if d.eof {
199
                        err = io.EOF
200
                }
201
                return
202
        }
203
204
        for len(p) > 0 {
205
                // read from buffer
206
                if length := d.end - d.n; length > 0 {
207
                        copied := utils.Min(length, len(p))
208
                        n += copy(p[:copied], d.buf[d.n:d.n+copied])
209
                        d.n += copied
210
                        p = p[copied:]
211
                        continue
212
                }
213
214
                // buffer is empty, write new buffer
215
                if d.eof {
216
                        return n, io.EOF
217
                }
218
                d.n = 0
219
                d.end = 0
220
                for {
221
                        nr, err = d.r.Read(d.buf[d.n:d.size])
222
                        d.eof = errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF)
223
                        if err != nil && !d.eof {
224
                                return
225
                        }
226
227
                        d.n += nr
228
                        if d.n < d.size && !d.eof {
229
                                continue
230
                        }
231
232
                        nc, err = d.bm.CryptBlocks(d.unsealed, d.buf[:d.n], d.unsealBuf)
233
                        if err != nil {
234
                                return
235
                        }
236
237
                        d.end += copy(d.buf[:nc], d.unsealed[:nc])
238
                        d.n = 0
239
                        break
240
                }
241
        }
242
243
        return
244
}
func enc.Write
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

175
func (e *enc) Write(p []byte) (n int, err error) {
176
        if e.buf == nil {
177
                var dst []byte
178
                dst, err = encrypt(e.bm, p)
179
                if err != nil {
180
                        return
181
                }
182
                n = len(p)
183
                _, err = e.w.Write(dst)
184
                return
185
        }
186
187
        written := 0
188
        for len(p) > 0 {
189
                nCopy := utils.Min(len(p), len(e.buf)-e.n)
190
                copy(e.buf[e.n:], p[:nCopy])
191
                e.n += nCopy
192
                written += nCopy
193
                p = p[nCopy:]
194
195
                if e.n == len(e.buf) {
196
                        if err = e.flush(); err != nil {
197
                                return written, err
198
                        }
199
                }
200
        }
201
202
        return written, nil
203
}
func NewDecFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

142
func NewDecFunc(algo Algorithm, mode Mode, key, iv []byte) func(r io.Reader) io.ReadCloser {
143
        bm, err := getDecrypter(algo, mode, key, iv)
144
        if err != nil {
145
                panic(err)
146
        }
147
        if !bm.CipherMode().SupportStream() {
148
                panic(ErrNotSupportStream)
149
        }
150
151
        var (
152
                buf, unsealed, unsealBuf []byte
153
                cb                       func()
154
                size                     int
155
        )
156
157
        if size = bm.CipherBlockSize(); size > 0 {
158
                var bcb, ucb, ubcb func()
159
                buf, bcb = utils.BytesPool.Get(size)
160
                unsealed, ucb = utils.BytesPool.Get(bm.PlainBlockSize())
161
                unsealBuf, ubcb = utils.BytesPool.Get(bm.PlainBlockSize())
162
                cb = func() { bcb(); ucb(); ubcb() }
163
        }
164
165
        return func(r io.Reader) io.ReadCloser {
166
                return &dec{
167
                        bm:        bm,
168
                        r:         r,
169
                        buf:       buf,
170
                        cb:        cb,
171
                        n:         0,
172
                        end:       0,
173
                        size:      size,
174
                        eof:       false,
175
                        unsealed:  unsealed,
176
                        unsealBuf: unsealBuf,
177
                }
178
        }
179
}
func @19:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

19
func(src []byte) (dst []byte, err error) {
20
                dst, err = decrypt(bm, src)
21
                if err != nil {
22
                        return
23
                }
24
                if mode.ShouldPadding() {
25
                        dst, err = PKCS7Unpad(dst)
26
                }
27
                return
28
        }
func DecryptStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

31
func DecryptStreamFunc(algo Algorithm, mode Mode, key, iv []byte) (
32
        dec func(dst io.Writer, src io.Reader) (err error), err error) {
33
        var fn func(src io.Reader) io.ReadCloser
34
35
        _, err = utils.Catch(func() { fn = NewDecFunc(algo, mode, key, iv) })
36
        if err != nil {
37
                return
38
        }
39
40
        dec = func(dst io.Writer, src io.Reader) (err error) {
41
                buf, cb := utils.BytesPool.Get(defaultBlockSize * blockSizeTimes)
42
                defer cb()
43
44
                wrapper := fn(src)
45
                defer utils.CloseAnyway(wrapper)
46
                _, err = io.CopyBuffer(dst, wrapper, buf)
47
                return
48
        }
49
50
        return
51
}
func EncryptBytesFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

11
func EncryptBytesFunc(algo Algorithm, mode Mode, key, iv []byte) (
12
        enc func(src []byte) (dst []byte, err error), err error) {
13
        bm, err := getEncrypter(algo, mode, key, iv)
14
        if err != nil {
15
                return
16
        }
17
        mode = bm.CipherMode()
18
        plainBlockSize := bm.PlainBlockSize()
19
        return func(src []byte) (dst []byte, err error) {
20
                if mode.ShouldPadding() {
21
                        src = PKCS7Pad(src, plainBlockSize)
22
                }
23
                return encrypt(bm, src)
24
        }, err
25
}
func blockModeWrapper.CryptBlocks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/block_mode_wrapper.go:

75
func (b *blockModeWrapper) CryptBlocks(dst, src, buf []byte) (n int, err error) {
76
        if len(src) == 0 {
77
                return
78
        }
79
        n = len(src)
80
        switch {
81
        case b.blockMode != nil:
82
                b.blockMode.CryptBlocks(dst, src)
83
        case b.block != nil:
84
                if b.isEncoder {
85
                        b.block.Encrypt(dst, src)
86
                } else {
87
                        b.block.Decrypt(dst, src)
88
                }
89
        case b.stream != nil:
90
                b.stream.XORKeyStream(dst, src)
91
        default:
92
                copy(dst, src)
93
        }
94
        return
95
}
func aeadEncryptWrapper.CryptBlocks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

53
func (a *aeadEncryptWrapper) CryptBlocks(dst, src, buf []byte) (n int, err error) {
54
        if len(src) == 0 {
55
                return
56
        }
57
58
        nonce, cb := utils.BytesPool.Get(a.nonceSize)
59
        defer cb()
60
        if _, err = utils.CryptoRandom(nonce); err != nil {
61
                return
62
        }
63
64
        sealed := a.Seal(buf[:0], nonce, src[:utils.Min(a.plainBlockSize, len(src))], nil)
65
        copy(dst[:a.nonceSize], nonce)
66
        copy(dst[a.nonceSize:], sealed)
67
        n = len(nonce) + len(sealed)
68
        return
69
}
func @126:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

126
func(key []byte) (bm blockMode, err error) {
127
                        cipherAEAD, err := chacha20poly1305.NewX(key)
128
                        if err != nil {
129
                                return
130
                        }
131
                        bm = newAEADEncryptWrapper(cipherAEAD, defaultBlockSize, modeStream)
132
                        return
133
                }
func @136:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

136
func(key []byte) (bm blockMode, err error) {
137
                        cipher, err := rc4.NewCipher(key)
138
                        if err != nil {
139
                                return
140
                        }
141
                        bm = &rc4Wrapper{rc: cipher}
142
                        return
143
                }
func @118:30
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

118
func(key []byte) (bm blockMode, err error) {
119
                        cipherAEAD, err := chacha20poly1305.New(key)
120
                        if err != nil {
121
                                return
122
                        }
123
                        bm = newAEADEncryptWrapper(cipherAEAD, defaultBlockSize, modeStream)
124
                        return
125
                }
func @144:30
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

144
func(key []byte) (bm blockMode, err error) {
145
                        cipherAEAD, err := chacha20poly1305.New(key)
146
                        if err != nil {
147
                                return
148
                        }
149
                        bm = newAEADDecryptWrapper(cipherAEAD, defaultBlockSize, modeStream)
150
                        return
151
                }
func @110:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

110
func(key []byte) (bm blockMode, err error) {
111
                        cipher, err := rc4.NewCipher(key)
112
                        if err != nil {
113
                                return
114
                        }
115
                        bm = &rc4Wrapper{rc: cipher}
116
                        return
117
                }
func DecryptBytesFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

12
func DecryptBytesFunc(algo Algorithm, mode Mode, key, iv []byte) (
13
        enc func(src []byte) (dst []byte, err error), err error) {
14
        bm, err := getDecrypter(algo, mode, key, iv)
15
        if err != nil {
16
                return
17
        }
18
        mode = bm.CipherMode()
19
        return func(src []byte) (dst []byte, err error) {
20
                dst, err = decrypt(bm, src)
21
                if err != nil {
22
                        return
23
                }
24
                if mode.ShouldPadding() {
25
                        dst, err = PKCS7Unpad(dst)
26
                }
27
                return
28
        }, err
29
}
func rc4Wrapper.CryptBlocks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/rc4_wrapper.go:

12
func (r *rc4Wrapper) CryptBlocks(dst, src, buf []byte) (n int, err error) {
13
        if len(src) == 0 {
14
                return
15
        }
16
        r.rc.XORKeyStream(dst, src)
17
        n = len(src)
18
        return
19
}
func @152:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

152
func(key []byte) (bm blockMode, err error) {
153
                        cipherAEAD, err := chacha20poly1305.NewX(key)
154
                        if err != nil {
155
                                return
156
                        }
157
                        bm = newAEADDecryptWrapper(cipherAEAD, defaultBlockSize, modeStream)
158
                        return
159
                }
func @99:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

99
func(b cipher.Block, iv []byte) (bm blockMode, err error) {
100
                        cipherAEAD, err := cipher.NewGCM(b)
101
                        if err != nil {
102
                                return
103
                        }
104
                        bm = newAEADDecryptWrapper(cipherAEAD, b.BlockSize(), ModeGCM)
105
                        return
106
                }
func @64:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/types.go:

64
func(b cipher.Block, iv []byte) (e blockMode, err error) {
65
                        aead, err := cipher.NewGCM(b)
66
                        if err != nil {
67
                                return
68
                        }
69
                        e = newAEADEncryptWrapper(aead, b.BlockSize(), ModeGCM)
70
                        return
71
                }
func aeadDecryptWrapper.CryptBlocks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/aead_wrapper.go:

79
func (a *aeadDecryptWrapper) CryptBlocks(dst, src, buf []byte) (n int, err error) {
80
        if len(src) == 0 {
81
                return
82
        }
83
        sealedSize := utils.Min(a.sealedSize, len(src)-a.nonceSize)
84
        if sealedSize < 0 {
85
                return 0, errors.New("input not full blocks when decrypt")
86
        }
87
88
        nonce := src[:a.nonceSize]
89
        src = src[a.nonceSize:]
90
        unsealed, err := a.Open(buf[:0], nonce, src[:sealedSize], nil)
91
        if err != nil {
92
                return
93
        }
94
95
        copy(dst, unsealed)
96
        n = len(unsealed)
97
        return
98
}
func PKCS7Pad
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/padding.go:

9
func PKCS7Pad(data []byte, blockSize int) []byte {
10
        if blockSize == 0 {
11
                return data
12
        }
13
        padding := blockSize - len(data)%blockSize
14
        return append(data, bytes.Repeat([]byte{byte(padding)}, padding)...)
15
}
func getEncrypter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

95
func getEncrypter(algo Algorithm, mode Mode, key, iv []byte) (bm blockMode, err error) {
96
        if blockMapping, ok := cipherBlockMapping[algo]; ok {
97
                var cipherBlock cipher.Block
98
                cipherBlock, err = blockMapping(key)
99
                if err != nil {
100
                        return
101
                }
102
                modeMapping, ok := encryptModeMapping[mode]
103
                if !ok {
104
                        return nil, fmt.Errorf("unknown cipher mode %+v", mode)
105
                }
106
                bm, err = modeMapping(cipherBlock, iv)
107
                if err != nil {
108
                        return
109
                }
110
        }
111
112
        // stream
113
        if bm == nil {
114
                blockMapping, ok := streamEncryptMapping[algo]
115
                if !ok {
116
                        return nil, fmt.Errorf("unknown cipher algorithm %+v", algo)
117
                }
118
                if bm, err = blockMapping(key); err != nil {
119
                        return
120
                }
121
        }
122
123
        if bm == nil {
124
                return nil, fmt.Errorf("unknown cipher algorithm(%+v) or mode(%+v)", algo, mode)
125
        }
126
127
        return
128
}
func getDecrypter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/decrypt.go:

93
func getDecrypter(algo Algorithm, mode Mode, key, iv []byte) (bm blockMode, err error) {
94
        if blockMapping, ok := cipherBlockMapping[algo]; ok {
95
                var cipherBlock cipher.Block
96
                cipherBlock, err = blockMapping(key)
97
                if err != nil {
98
                        return
99
                }
100
                modeMapping, ok := decryptModeMapping[mode]
101
                if !ok {
102
                        return nil, fmt.Errorf("unknown cipher mode %+v", mode)
103
                }
104
                bm, err = modeMapping(cipherBlock, iv)
105
                if err != nil {
106
                        return
107
                }
108
        }
109
110
        // stream
111
        if bm == nil {
112
                blockMapping, ok := streamDecryptMapping[algo]
113
                if !ok {
114
                        return nil, fmt.Errorf("unknown cipher algorithm %+v", algo)
115
                }
116
                if bm, err = blockMapping(key); err != nil {
117
                        return
118
                }
119
        }
120
121
        if bm == nil {
122
                return nil, fmt.Errorf("unknown cipher algorithm(%+v) or mode(%+v)", algo, mode)
123
        }
124
125
        return
126
}
func enc.flush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/encrypt.go:

205
func (e *enc) flush() (err error) {
206
        if e.buf == nil {
207
                return
208
        }
209
210
        n, err := e.bm.CryptBlocks(e.sealed, e.buf[:e.n], e.sealBuf)
211
        if err != nil {
212
                return
213
        }
214
215
        _, err = e.w.Write(e.sealed[:n])
216
        if err != nil {
217
                return err
218
        }
219
220
        e.n = 0
221
        return
222
}
func PKCS7Unpad
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/padding.go:

18
func PKCS7Unpad(data []byte) ([]byte, error) {
19
        length := len(data)
20
        if length == 0 {
21
                return data, nil
22
        }
23
        padding := int(data[length-1])
24
        if padding == 0 || padding > len(data) {
25
                return data, errors.New("invalid pkcs7 padding (padding size > data)")
26
        }
27
        for i := 1; i < padding; i++ {
28
                if data[length-1-i] != byte(padding) {
29
                        return data, errors.New("invalid pkcs7 padding (pad[i] != padding text)")
30
                }
31
        }
32
33
        return data[:(length - padding)], nil
34
}
func ParseMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

65
func ParseMode(s any) Mode {
66
        switch v := s.(type) {
67
        case string:
68
                if enumList := modeEnum.Enum(v); len(enumList) > 0 {
69
                        return enumList[0]
70
                }
71
        case Mode:
72
                return v
73
        default:
74
                return Mode(cast.ToInt(s))
75
        }
76
        return ModeUnknown
77
}
func ParseAlgorithm
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go:

49
func ParseAlgorithm(s any) Algorithm {
50
        switch v := s.(type) {
51
        case string:
52
                if enumList := algorithmEnum.Enum(v); len(enumList) > 0 {
53
                        return enumList[0]
54
                }
55
        case Algorithm:
56
                return v
57
        default:
58
                return Algorithm(cast.ToInt(s))
59
        }
60
        return AlgorithmUnknown
61
}
func Algorithm.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/algorithm_enum.go:

37
func (e Algorithm) Value() uint8 {
38
        return uint8(e)
39
}
func Mode.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cipher/mode_enum.go:

41
func (m Mode) Value() uint8 {
42
        return uint8(m)
43
}
Package Overview: github.com/wfusion/gofusion/common/utils/clone 37.3%

Please select a function to see what's left for testing.

init(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 14/14
Allocator.lookupStructType(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 9/9
SliceComparable(...) github.com/wfusion/gofusion/common/utils/clone/base.go 100.0% 5/5
cloneState.cloneInterface(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 100.0% 5/5
cloneState.cloneStruct(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 100.0% 4/4
IsScalar(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 4/4
Allocator.MarkAsOpaquePointer(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 3/3
cloneState.cloneArray(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 100.0% 3/3
parseReflectValue(...) github.com/wfusion/gofusion/common/utils/clone/interfacedata.go 100.0% 3/3
MakeCloner(...) github.com/wfusion/gofusion/common/utils/clone/cloner.go 100.0% 1/1
SetCustomFunc(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 100.0% 1/1
structType.CanShadowCopy(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 1/1
MarkAsScalar(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 100.0% 1/1
Allocator.MakeMap(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
Allocator.MakeSlice(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
Slowly(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 100.0% 1/1
heapNew(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
heapMakeSlice(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
heapMakeMap(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
setCustomFunc(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 1/1
markAsOpaquePointer(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 1/1
markAsScalar(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 1/1
Allocator.New(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 100.0% 1/1
mapIter(...) github.com/wfusion/gofusion/common/utils/clone/mapiter_go112.go 100.0% 1/1
Clone(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 100.0% 1/1
Cloner.CloneSlowly(...) github.com/wfusion/gofusion/common/utils/clone/cloner.go 100.0% 1/1
Cloner.Clone(...) github.com/wfusion/gofusion/common/utils/clone/cloner.go 100.0% 1/1
MarkAsOpaquePointer(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 100.0% 1/1
cloneState.cloneSlice(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 95.7% 22/23
cloneState.copyStruct(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 94.7% 18/19
cloneState.cloneMap(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 93.8% 15/16
init(...) github.com/wfusion/gofusion/common/utils/clone/interfacedata.go 90.9% 10/11
Allocator.loadStructType(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 85.3% 29/34
Allocator.isOpaquePointer(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 83.3% 5/6
cloneSlowly(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 80.0% 4/5
clone(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 80.0% 4/5
cloneState.clone(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 75.0% 9/12
cloneState.copyArray(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 75.0% 6/8
Allocator.cloneSlowly(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 75.0% 6/8
Allocator.MarkAsScalar(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 75.0% 3/4
cloneState.clonePtr(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 72.4% 21/29
forceClearROFlag(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 69.2% 9/13
Allocator.clone(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 66.7% 4/6
Allocator.SetCustomFunc(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 57.1% 4/7
structType.Init(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 54.5% 6/11
shadowCopy(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 50.0% 28/56
cloneState.fix(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 50.0% 2/4
copyScalarValue(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 26.9% 7/26
fixState.fixMap(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/46
fixState.fixStruct(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/32
fixState.fixArray(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/29
fixState.fixSlice(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/29
wrap(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/24
newAllocator(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/15
fixState.fixInterface(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/15
fixState.fix(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/12
fixState.fixPtr(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/11
cloneState.cloneString(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/10
forceSetMapIndex(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/9
undo(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/8
AllocatorMethods.makeChan(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/7
@90:48(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 0.0% 0/7
AllocatorMethods.new(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/7
unwrap(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/7
AllocatorMethods.makeMap(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/7
AllocatorMethods.makeSlice(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/7
isWrapped(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/6
origin(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/6
Map(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/6
Slice(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/6
@75:44(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 0.0% 0/5
DecimalPtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/5
ComparablePtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/5
AllocatorMethods.isScalar(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/5
validateChecksum(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/5
SliceComparablePtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/5
TimePtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/5
makeChecksum(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/4
TimeLocationPtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/4
@83:16(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 0.0% 0/4
AllocatorMethods.parent(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/3
@69:45(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 0.0% 0/3
@63:45(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 0.0% 0/3
GormModelPtr(...) github.com/wfusion/gofusion/common/utils/clone/base.go 0.0% 0/3
fixState.new(...) github.com/wfusion/gofusion/common/utils/clone/clone.go 0.0% 0/1
Undo(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 0.0% 0/1
Unwrap(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 0.0% 0/1
heapMakeChan(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/1
Allocator.CloneSlowly(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/1
Allocator.Clone(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/1
Allocator.MakeChan(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/1
NewAllocator(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 0.0% 0/1
@42:11(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/1
Wrap(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 0.0% 0/1
@60:11(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/1
@78:11(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/1
getOrigin(...) github.com/wfusion/gofusion/common/utils/clone/wrapper.go 0.0% 0/1
@96:11(...) github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go 0.0% 0/1
FromHeap(...) github.com/wfusion/gofusion/common/utils/clone/api_go118.go 0.0% 0/1
fromHeap(...) github.com/wfusion/gofusion/common/utils/clone/allocator.go 0.0% 0/1
emptyCloneFunc(...) github.com/wfusion/gofusion/common/utils/clone/structtype.go 100.0% 0/0
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

28
func init() {
29
        // Some well-known scalar-like structs.
30
        MarkAsScalar(reflect.TypeOf(time.Time{}))
31
        MarkAsScalar(reflect.TypeOf(reflect.Value{}))
32
33
        // Special case for elliptic.Curve which is used by TLS ECC certificate.
34
        // Package crypto/tls uses elliptic.Curve as enum values
35
        // so that they should be treated as opaque pointers.
36
        //
37
        // As elliptic.Curve is an interface, it can be *elliptic.CurveParam or elliptic.p256Curve.
38
        MarkAsOpaquePointer(reflect.TypeOf(&elliptic.CurveParams{}))
39
        curves := []elliptic.Curve{
40
                elliptic.P224(),
41
                elliptic.P256(),
42
                elliptic.P384(),
43
                elliptic.P521(),
44
        }
45
46
        for _, curve := range curves {
47
                MarkAsOpaquePointer(reflect.ValueOf(curve).Type())
48
        }
49
50
        // Special case for reflect.Type (actually *reflect.rtype):
51
        // The *reflect.rtype should not be copied as it is immutable and
52
        // may point to a variable that actual type is not reflect.rtype,
53
        // e.g. *reflect.arrayType or *reflect.chanType.
54
        MarkAsOpaquePointer(reflect.TypeOf(reflect.TypeOf(0)))
55
56
        // Some well-known no-copy structs.
57
        //
58
        // Almost all structs defined in package "sync" and "go.uber.org/atomic" are set
59
        // except `sync.Once` which can be safely cloned with a correct done value.
60
        SetCustomFunc(reflect.TypeOf(sync.Mutex{}), emptyCloneFunc)
61
        SetCustomFunc(reflect.TypeOf(sync.RWMutex{}), emptyCloneFunc)
62
        SetCustomFunc(reflect.TypeOf(sync.WaitGroup{}), emptyCloneFunc)
63
        SetCustomFunc(reflect.TypeOf(sync.Cond{}), func(allocator *Allocator, old, new reflect.Value) {
64
                // Copy the New func from old value.
65
                oldL := old.FieldByName("L")
66
                newL := allocator.Clone(oldL)
67
                new.FieldByName("L").Set(newL)
68
        })
69
        SetCustomFunc(reflect.TypeOf(sync.Pool{}), func(allocator *Allocator, old, new reflect.Value) {
70
                // Copy the New func from old value.
71
                oldFn := old.FieldByName("New")
72
                newFn := allocator.Clone(oldFn)
73
                new.FieldByName("New").Set(newFn)
74
        })
75
        SetCustomFunc(reflect.TypeOf(sync.Map{}), func(allocator *Allocator, old, new reflect.Value) {
76
                if !old.CanAddr() {
77
                        return
78
                }
79
80
                // Clone all values inside sync.Map.
81
                oldMap := old.Addr().Interface().(*sync.Map)
82
                newMap := new.Addr().Interface().(*sync.Map)
83
                oldMap.Range(func(key, value interface{}) bool {
84
                        k := clone(allocator, key)
85
                        v := clone(allocator, value)
86
                        newMap.Store(k, v)
87
                        return true
88
                })
89
        })
90
        SetCustomFunc(reflect.TypeOf(atomic.Value{}), func(allocator *Allocator, old, new reflect.Value) {
91
                if !old.CanAddr() {
92
                        return
93
                }
94
95
                // Clone value inside atomic.Value.
96
                oldValue := old.Addr().Interface().(*atomic.Value)
97
                newValue := new.Addr().Interface().(*atomic.Value)
98
                v := oldValue.Load()
99
                cloned := clone(allocator, v)
100
                newValue.Store(cloned)
101
        })
102
}
func Allocator.lookupStructType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

218
func (a *Allocator) lookupStructType(t reflect.Type) (st structType, ok bool) {
219
        var v interface{}
220
        current := a
221
222
        for current != nil {
223
                v, ok = current.cachedStructTypes.Load(t)
224
225
                if ok {
226
                        st = v.(structType)
227
                        return
228
                }
229
230
                current = current.parent
231
        }
232
233
        return
234
}
func SliceComparable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

19
func SliceComparable[T comparable, TS ~[]T](s TS) (d TS) {
20
        if s == nil {
21
                return
22
        }
23
        d = make(TS, len(s), cap(s))
24
        copy(d, s)
25
        return
26
}
func cloneState.cloneInterface
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

106
func (state *cloneState) cloneInterface(v reflect.Value) reflect.Value {
107
        if v.IsNil() {
108
                return reflect.Zero(v.Type())
109
        }
110
111
        t := v.Type()
112
        elem := v.Elem()
113
        return state.clone(elem).Convert(elem.Type()).Convert(t)
114
}
func cloneState.cloneStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

266
func (state *cloneState) cloneStruct(v reflect.Value) reflect.Value {
267
        t := v.Type()
268
        nv := state.allocator.New(t)
269
        state.copyStruct(v, nv)
270
        return nv.Elem()
271
}
func IsScalar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

188
func IsScalar(k reflect.Kind) bool {
189
        switch k {
190
        case reflect.Bool,
191
                reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
192
                reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
193
                reflect.Float32, reflect.Float64,
194
                reflect.Complex64, reflect.Complex128,
195
                reflect.Func,
196
                reflect.UnsafePointer,
197
                reflect.Invalid:
198
                return true
199
200
        case reflect.String:
201
                // If arena is not enabled, string can be copied as scalar safely
202
                // as it's immutable by design.
203
                return !arenaIsEnabled
204
        }
205
206
        return false
207
}
func Allocator.MarkAsOpaquePointer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

274
func (a *Allocator) MarkAsOpaquePointer(t reflect.Type) {
275
        if t.Kind() != reflect.Ptr {
276
                return
277
        }
278
279
        a.cachedPointerTypes.Store(t, struct{}{})
280
}
func cloneState.cloneArray
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

85
func (state *cloneState) cloneArray(v reflect.Value) reflect.Value {
86
        dst := state.allocator.New(v.Type())
87
        state.copyArray(v, dst)
88
        return dst.Elem()
89
}
func parseReflectValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/interfacedata.go:

46
func parseReflectValue(v reflect.Value) interfaceData {
47
        pv := (unsafe.Pointer)(uintptr(unsafe.Pointer(&v)) + reflectValuePtrOffset)
48
        ptr := *(*unsafe.Pointer)(pv)
49
        return *(*interfaceData)(ptr)
50
}
func MakeCloner
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/cloner.go:

12
func MakeCloner(allocator *Allocator) Cloner {
13
        return Cloner{
14
                allocator: allocator,
15
        }
16
}
func SetCustomFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

97
func SetCustomFunc(t reflect.Type, fn Func) {
98
        setCustomFunc(t, fn)
99
}
func structType.CanShadowCopy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

172
func (st *structType) CanShadowCopy() bool {
173
        return len(st.PointerFields) == 0 && st.fn == nil
174
}
func MarkAsScalar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

89
func MarkAsScalar(t reflect.Type) {
90
        markAsScalar(t)
91
}
func Allocator.MakeMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

89
func (a *Allocator) MakeMap(t reflect.Type, n int) reflect.Value {
90
        return a.makeMap(a.pool, t, n)
91
}
func Allocator.MakeSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

84
func (a *Allocator) MakeSlice(t reflect.Type, len, cap int) reflect.Value {
85
        return a.makeSlice(a.pool, t, len, cap)
86
}
func Slowly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

35
func Slowly[T any](t T) T {
36
        return cloner.CloneSlowly(t).(T)
37
}
func heapNew
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

300
func heapNew(pool unsafe.Pointer, t reflect.Type) reflect.Value {
301
        return reflect.New(t)
302
}
func heapMakeSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

304
func heapMakeSlice(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value {
305
        return reflect.MakeSlice(t, len, cap)
306
}
func heapMakeMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

308
func heapMakeMap(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value {
309
        return reflect.MakeMapWithSize(t, n)
310
}
func setCustomFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

144
func setCustomFunc(t reflect.Type, fn Func) {
145
        defaultAllocator.SetCustomFunc(t, fn)
146
}
func markAsOpaquePointer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

125
func markAsOpaquePointer(t reflect.Type) {
126
        defaultAllocator.MarkAsOpaquePointer(t)
127
}
func markAsScalar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

114
func markAsScalar(t reflect.Type) {
115
        defaultAllocator.MarkAsScalar(t)
116
}
func Allocator.New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

79
func (a *Allocator) New(t reflect.Type) reflect.Value {
80
        return a.new(a.pool, t)
81
}
func mapIter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/mapiter_go112.go:

13
func mapIter(m reflect.Value) *reflect.MapIter {
14
        return m.MapRange()
15
}
func Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

27
func Clone[T any](t T) T {
28
        return cloner.Clone(t).(T)
29
}
func Cloner.CloneSlowly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/cloner.go:

25
func (c Cloner) CloneSlowly(v interface{}) interface{} {
26
        return cloneSlowly(c.allocator, v)
27
}
func Cloner.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/cloner.go:

19
func (c Cloner) Clone(v interface{}) interface{} {
20
        return clone(c.allocator, v)
21
}
func MarkAsOpaquePointer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

75
func MarkAsOpaquePointer(t reflect.Type) {
76
        markAsOpaquePointer(t)
77
}
func cloneState.cloneSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

217
func (state *cloneState) cloneSlice(v reflect.Value) reflect.Value {
218
        if v.IsNil() {
219
                return reflect.Zero(v.Type())
220
        }
221
222
        t := v.Type()
223
        num := v.Len()
224
225
        if state.visited != nil {
226
                vst := visit{
227
                        p:     v.Pointer(),
228
                        extra: num,
229
                        t:     t,
230
                }
231
232
                if val, ok := state.visited[vst]; ok {
233
                        return val
234
                }
235
        }
236
237
        c := v.Cap()
238
        nv := state.allocator.MakeSlice(t, num, c)
239
240
        if state.visited != nil {
241
                vst := visit{
242
                        p:     v.Pointer(),
243
                        extra: num,
244
                        t:     t,
245
                }
246
                state.visited[vst] = nv
247
        }
248
249
        // For scalar slice, copy underlying values directly.
250
        if state.allocator.isScalar(t.Elem().Kind()) {
251
                src := unsafe.Pointer(v.Pointer())
252
                dst := unsafe.Pointer(nv.Pointer())
253
                sz := int(t.Elem().Size())
254
                l := num * sz
255
                cc := c * sz
256
                copy((*[maxByteSize]byte)(dst)[:l:cc], (*[maxByteSize]byte)(src)[:l:cc])
257
        } else {
258
                for i := 0; i < num; i++ {
259
                        nv.Index(i).Set(state.clone(v.Index(i)))
260
                }
261
        }
262
263
        return nv
264
}
func cloneState.copyStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

294
func (state *cloneState) copyStruct(src, nv reflect.Value) {
295
        t := src.Type()
296
        st := state.allocator.loadStructType(t)
297
        ptr := unsafe.Pointer(nv.Pointer())
298
299
        if st.Init(state.allocator, src, nv, state.skipCustomFuncValue == src) {
300
                return
301
        }
302
303
        for _, pf := range st.PointerFields {
304
                i := int(pf.Index)
305
                p := unsafe.Pointer(uintptr(ptr) + pf.Offset)
306
                field := src.Field(i)
307
308
                // This field can be referenced by a pointer or interface inside itself.
309
                // Put the pointer to this field to visited to avoid any error.
310
                //
311
                // See https://github.com/huandu/go-clone/issues/3.
312
                if state.visited != nil && field.CanAddr() {
313
                        ft := field.Type()
314
                        fp := field.Addr().Pointer()
315
                        vst := visit{
316
                                p: fp,
317
                                t: reflect.PtrTo(ft),
318
                        }
319
                        nv := reflect.NewAt(ft, p)
320
321
                        // The address of this field was visited, so fp must be a cycle pointer.
322
                        // As this field is not fully cloned, the val stored in visited[visit] must be wrong.
323
                        // It must be replaced by nv which will be the right value (it's incomplete right now).
324
                        //
325
                        // Unfortunately, if the val was used by previous clone routines,
326
                        // there is no easy way to fix wrong values - all pointers must be traversed and fixed.
327
                        if val, ok := state.visited[vst]; ok {
328
                                state.invalid[visit{
329
                                        p: val.Pointer(),
330
                                        t: vst.t,
331
                                }] = nv
332
                        }
333
334
                        state.visited[vst] = nv
335
                }
336
337
                v := state.clone(field)
338
                shadowCopy(v, p)
339
        }
340
}
func cloneState.cloneMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

116
func (state *cloneState) cloneMap(v reflect.Value) reflect.Value {
117
        if v.IsNil() {
118
                return reflect.Zero(v.Type())
119
        }
120
121
        t := v.Type()
122
123
        if state.visited != nil {
124
                vst := visit{
125
                        p: v.Pointer(),
126
                        t: t,
127
                }
128
129
                if val, ok := state.visited[vst]; ok {
130
                        return val
131
                }
132
        }
133
134
        nv := state.allocator.MakeMap(t, v.Len())
135
136
        if state.visited != nil {
137
                vst := visit{
138
                        p: v.Pointer(),
139
                        t: t,
140
                }
141
                state.visited[vst] = nv
142
        }
143
144
        for iter := mapIter(v); iter.Next(); {
145
                key := state.clone(iter.Key())
146
                value := state.clone(iter.Value())
147
                nv.SetMapIndex(key, value)
148
        }
149
150
        return nv
151
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/interfacedata.go:

24
func init() {
25
        t := reflect.TypeOf(reflect.Value{})
26
        found := false
27
        fields := t.NumField()
28
29
        for i := 0; i < fields; i++ {
30
                field := t.Field(i)
31
32
                if field.Type.Kind() == reflect.UnsafePointer {
33
                        found = true
34
                        reflectValuePtrOffset = field.Offset
35
                        break
36
                }
37
        }
38
39
        if !found {
40
                panic("go-clone: fail to find internal ptr field in reflect.Value")
41
        }
42
}
func Allocator.loadStructType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

145
func (a *Allocator) loadStructType(t reflect.Type) (st structType) {
146
        st, ok := a.lookupStructType(t)
147
148
        if ok {
149
                return
150
        }
151
152
        num := t.NumField()
153
        pointerFields := make([]structFieldType, 0, num)
154
155
        // Find pointer fields in depth-first order.
156
        for i := 0; i < num; i++ {
157
                field := t.Field(i)
158
                ft := field.Type
159
                k := ft.Kind()
160
161
                if a.isScalar(k) {
162
                        continue
163
                }
164
165
                switch k {
166
                case reflect.Array:
167
                        if ft.Len() == 0 {
168
                                continue
169
                        }
170
171
                        elem := ft.Elem()
172
173
                        if a.isScalar(elem.Kind()) {
174
                                continue
175
                        }
176
177
                        if elem.Kind() == reflect.Struct {
178
                                if fst := a.loadStructType(elem); fst.CanShadowCopy() {
179
                                        continue
180
                                }
181
                        }
182
                case reflect.Struct:
183
                        if fst := a.loadStructType(ft); fst.CanShadowCopy() {
184
                                continue
185
                        }
186
                }
187
188
                pointerFields = append(pointerFields, structFieldType{
189
                        Offset: field.Offset,
190
                        Index:  i,
191
                })
192
        }
193
194
        if len(pointerFields) == 0 {
195
                pointerFields = nil // Release memory ASAP.
196
        }
197
198
        st = structType{
199
                PointerFields: pointerFields,
200
        }
201
202
        // Load custom function.
203
        current := a
204
205
        for current != nil {
206
                if fn, ok := current.cachedCustomFuncTypes.Load(t); ok {
207
                        st.fn = fn.(Func)
208
                        break
209
                }
210
211
                current = current.parent
212
        }
213
214
        a.cachedStructTypes.LoadOrStore(t, st)
215
        return
216
}
func Allocator.isOpaquePointer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

236
func (a *Allocator) isOpaquePointer(t reflect.Type) (ok bool) {
237
        current := a
238
239
        for current != nil {
240
                if _, ok = current.cachedPointerTypes.Load(t); ok {
241
                        return
242
                }
243
244
                current = current.parent
245
        }
246
247
        return
248
}
func cloneSlowly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

29
func cloneSlowly(allocator *Allocator, v interface{}) interface{} {
30
        if v == nil {
31
                return nil
32
        }
33
34
        val := reflect.ValueOf(v)
35
        cloned := allocator.cloneSlowly(val, false)
36
        return cloned.Interface()
37
}
func clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

19
func clone(allocator *Allocator, v interface{}) interface{} {
20
        if v == nil {
21
                return nil
22
        }
23
24
        val := reflect.ValueOf(v)
25
        cloned := allocator.clone(val, false)
26
        return cloned.Interface()
27
}
func cloneState.clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

58
func (state *cloneState) clone(v reflect.Value) reflect.Value {
59
        if state.allocator.isScalar(v.Kind()) {
60
                return copyScalarValue(v)
61
        }
62
63
        switch v.Kind() {
64
        case reflect.Array:
65
                return state.cloneArray(v)
66
        case reflect.Chan:
67
                return state.allocator.MakeChan(v.Type(), v.Cap())
68
        case reflect.Interface:
69
                return state.cloneInterface(v)
70
        case reflect.Map:
71
                return state.cloneMap(v)
72
        case reflect.Ptr:
73
                return state.clonePtr(v)
74
        case reflect.Slice:
75
                return state.cloneSlice(v)
76
        case reflect.Struct:
77
                return state.cloneStruct(v)
78
        case reflect.String:
79
                return state.cloneString(v)
80
        default:
81
                panic(fmt.Errorf("go-clone: <bug> unsupported type `%v`", v.Type()))
82
        }
83
}
func cloneState.copyArray
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

91
func (state *cloneState) copyArray(src, nv reflect.Value) {
92
        p := unsafe.Pointer(nv.Pointer()) // dst must be a Ptr.
93
        dst := nv.Elem()
94
        num := src.Len()
95
96
        if state.allocator.isScalar(src.Type().Elem().Kind()) {
97
                shadowCopy(src, p)
98
                return
99
        }
100
101
        for i := 0; i < num; i++ {
102
                dst.Index(i).Set(state.clone(src.Index(i)))
103
        }
104
}
func Allocator.cloneSlowly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

125
func (a *Allocator) cloneSlowly(val reflect.Value, inCustomFunc bool) reflect.Value {
126
        if !val.IsValid() {
127
                return val
128
        }
129
130
        state := &cloneState{
131
                allocator: a,
132
                visited:   visitMap{},
133
                invalid:   invalidPointers{},
134
        }
135
136
        if inCustomFunc {
137
                state.skipCustomFuncValue = val
138
        }
139
140
        cloned := state.clone(val)
141
        state.fix(cloned)
142
        return cloned
143
}
func Allocator.MarkAsScalar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

259
func (a *Allocator) MarkAsScalar(t reflect.Type) {
260
        t = utils.IndirectType(t)
261
        if t.Kind() != reflect.Struct {
262
                return
263
        }
264
265
        a.cachedStructTypes.Store(t, zeroStructType)
266
}
func cloneState.clonePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

153
func (state *cloneState) clonePtr(v reflect.Value) reflect.Value {
154
        if v.IsNil() {
155
                return reflect.Zero(v.Type())
156
        }
157
158
        t := v.Type()
159
160
        if state.allocator.isOpaquePointer(t) {
161
                if v.CanInterface() {
162
                        return v
163
                }
164
165
                ptr := state.allocator.New(t)
166
                p := unsafe.Pointer(ptr.Pointer())
167
                shadowCopy(v, p)
168
                return ptr.Elem()
169
        }
170
171
        if state.visited != nil {
172
                vst := visit{
173
                        p: v.Pointer(),
174
                        t: t,
175
                }
176
177
                if val, ok := state.visited[vst]; ok {
178
                        return val
179
                }
180
        }
181
182
        src := v.Elem()
183
        elemType := src.Type()
184
        elemKind := src.Kind()
185
        nv := state.allocator.New(elemType)
186
187
        if state.visited != nil {
188
                vst := visit{
189
                        p: v.Pointer(),
190
                        t: t,
191
                }
192
                state.visited[vst] = nv
193
        }
194
195
        switch elemKind {
196
        case reflect.Struct:
197
                state.copyStruct(src, nv)
198
        case reflect.Array:
199
                state.copyArray(src, nv)
200
        default:
201
                nv.Elem().Set(state.clone(src))
202
        }
203
204
        // If this pointer is the address of a struct field and it's a cycle pointer,
205
        // it may be updated.
206
        if state.visited != nil {
207
                vst := visit{
208
                        p: v.Pointer(),
209
                        t: t,
210
                }
211
                nv = state.visited[vst]
212
        }
213
214
        return nv
215
}
func forceClearROFlag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

277
func forceClearROFlag(v reflect.Value) reflect.Value {
278
        var i interface{}
279
        indirect := 0
280
281
        // Save flagAddr.
282
        for v.CanAddr() {
283
                v = v.Addr()
284
                indirect++
285
        }
286
287
        v = v.Convert(typeOfInterface)
288
        nv := reflect.ValueOf(&i)
289
        *(*interfaceData)(unsafe.Pointer(nv.Pointer())) = parseReflectValue(v)
290
        cleared := nv.Elem().Elem()
291
292
        for indirect > 0 {
293
                cleared = cleared.Elem()
294
                indirect--
295
        }
296
297
        return cleared
298
}
func Allocator.clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

103
func (a *Allocator) clone(val reflect.Value, inCustomFunc bool) reflect.Value {
104
        if !val.IsValid() {
105
                return val
106
        }
107
108
        state := &cloneState{
109
                allocator: a,
110
        }
111
112
        if inCustomFunc {
113
                state.skipCustomFuncValue = val
114
        }
115
116
        return state.clone(val)
117
}
func Allocator.SetCustomFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

286
func (a *Allocator) SetCustomFunc(t reflect.Type, fn Func) {
287
        if fn == nil {
288
                a.cachedCustomFuncTypes.Delete(t)
289
                return
290
        }
291
292
        t = utils.IndirectType(t)
293
        if t.Kind() != reflect.Struct {
294
                return
295
        }
296
297
        a.cachedCustomFuncTypes.Store(t, fn)
298
}
func structType.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

153
func (st *structType) Init(allocator *Allocator, src, nv reflect.Value, noCustomFunc bool) (done bool) {
154
        dst := nv.Elem()
155
156
        if !noCustomFunc && st.fn != nil {
157
                if !src.CanInterface() {
158
                        src = forceClearROFlag(src)
159
                }
160
161
                st.fn(allocator, src, dst)
162
                done = true
163
                return
164
        }
165
166
        ptr := unsafe.Pointer(nv.Pointer())
167
        shadowCopy(src, ptr)
168
        done = len(st.PointerFields) == 0
169
        return
170
}
func shadowCopy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

344
func shadowCopy(src reflect.Value, p unsafe.Pointer) {
345
        switch src.Kind() {
346
        case reflect.Bool:
347
                *(*bool)(p) = src.Bool()
348
        case reflect.Int:
349
                *(*int)(p) = int(src.Int())
350
        case reflect.Int8:
351
                *(*int8)(p) = int8(src.Int())
352
        case reflect.Int16:
353
                *(*int16)(p) = int16(src.Int())
354
        case reflect.Int32:
355
                *(*int32)(p) = int32(src.Int())
356
        case reflect.Int64:
357
                *(*int64)(p) = src.Int()
358
        case reflect.Uint:
359
                *(*uint)(p) = uint(src.Uint())
360
        case reflect.Uint8:
361
                *(*uint8)(p) = uint8(src.Uint())
362
        case reflect.Uint16:
363
                *(*uint16)(p) = uint16(src.Uint())
364
        case reflect.Uint32:
365
                *(*uint32)(p) = uint32(src.Uint())
366
        case reflect.Uint64:
367
                *(*uint64)(p) = src.Uint()
368
        case reflect.Uintptr:
369
                *(*uintptr)(p) = uintptr(src.Uint())
370
        case reflect.Float32:
371
                *(*float32)(p) = float32(src.Float())
372
        case reflect.Float64:
373
                *(*float64)(p) = src.Float()
374
        case reflect.Complex64:
375
                *(*complex64)(p) = complex64(src.Complex())
376
        case reflect.Complex128:
377
                *(*complex128)(p) = src.Complex()
378
379
        case reflect.Array:
380
                t := src.Type()
381
382
                if src.CanAddr() {
383
                        srcPtr := unsafe.Pointer(src.UnsafeAddr())
384
                        sz := t.Size()
385
                        copy((*[maxByteSize]byte)(p)[:sz:sz], (*[maxByteSize]byte)(srcPtr)[:sz:sz])
386
                        return
387
                }
388
389
                val := reflect.NewAt(t, p).Elem()
390
391
                if src.CanInterface() {
392
                        val.Set(src)
393
                        return
394
                }
395
396
                sz := t.Elem().Size()
397
                num := src.Len()
398
399
                for i := 0; i < num; i++ {
400
                        elemPtr := unsafe.Pointer(uintptr(p) + uintptr(i)*sz)
401
                        shadowCopy(src.Index(i), elemPtr)
402
                }
403
        case reflect.Chan:
404
                *((*uintptr)(p)) = src.Pointer()
405
        case reflect.Func:
406
                t := src.Type()
407
                src = copyScalarValue(src)
408
                val := reflect.NewAt(t, p).Elem()
409
                val.Set(src)
410
        case reflect.Interface:
411
                *((*interfaceData)(p)) = parseReflectValue(src)
412
        case reflect.Map:
413
                *((*uintptr)(p)) = src.Pointer()
414
        case reflect.Ptr:
415
                *((*uintptr)(p)) = src.Pointer()
416
        case reflect.Slice:
417
                *(*sliceHeader)(p) = sliceHeader{
418
                        Data: src.Pointer(),
419
                        Len:  src.Len(),
420
                        Cap:  src.Cap(),
421
                }
422
        case reflect.String:
423
                s := src.String()
424
                val := reflect.NewAt(typeOfString, p).Elem()
425
                val.SetString(s)
426
        case reflect.Struct:
427
                t := src.Type()
428
                val := reflect.NewAt(t, p).Elem()
429
430
                if src.CanInterface() {
431
                        val.Set(src)
432
                        return
433
                }
434
435
                num := t.NumField()
436
437
                for i := 0; i < num; i++ {
438
                        field := t.Field(i)
439
                        fieldPtr := unsafe.Pointer(uintptr(p) + field.Offset)
440
                        shadowCopy(src.Field(i), fieldPtr)
441
                }
442
        case reflect.UnsafePointer:
443
                // There is no way to copy unsafe.Pointer value.
444
                *((*uintptr)(p)) = src.Pointer()
445
446
        default:
447
                panic(fmt.Errorf("go-clone: <bug> impossible type `%v` when cloning private field", src.Type()))
448
        }
449
}
func cloneState.fix
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

452
func (state *cloneState) fix(v reflect.Value) {
453
        if state == nil || len(state.invalid) == 0 {
454
                return
455
        }
456
457
        fix := &fixState{
458
                allocator: state.allocator,
459
                fixed:     fixMap{},
460
                invalid:   state.invalid,
461
        }
462
        fix.fix(v)
463
}
func copyScalarValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

209
func copyScalarValue(src reflect.Value) reflect.Value {
210
        if src.CanInterface() {
211
                return src
212
        }
213
214
        // src is an unexported field value. Copy its value.
215
        switch src.Kind() {
216
        case reflect.Bool:
217
                return reflect.ValueOf(src.Bool())
218
219
        case reflect.Int:
220
                return reflect.ValueOf(int(src.Int()))
221
        case reflect.Int8:
222
                return reflect.ValueOf(int8(src.Int()))
223
        case reflect.Int16:
224
                return reflect.ValueOf(int16(src.Int()))
225
        case reflect.Int32:
226
                return reflect.ValueOf(int32(src.Int()))
227
        case reflect.Int64:
228
                return reflect.ValueOf(src.Int())
229
230
        case reflect.Uint:
231
                return reflect.ValueOf(uint(src.Uint()))
232
        case reflect.Uint8:
233
                return reflect.ValueOf(uint8(src.Uint()))
234
        case reflect.Uint16:
235
                return reflect.ValueOf(uint16(src.Uint()))
236
        case reflect.Uint32:
237
                return reflect.ValueOf(uint32(src.Uint()))
238
        case reflect.Uint64:
239
                return reflect.ValueOf(src.Uint())
240
        case reflect.Uintptr:
241
                return reflect.ValueOf(uintptr(src.Uint()))
242
243
        case reflect.Float32:
244
                return reflect.ValueOf(float32(src.Float()))
245
        case reflect.Float64:
246
                return reflect.ValueOf(src.Float())
247
248
        case reflect.Complex64:
249
                return reflect.ValueOf(complex64(src.Complex()))
250
        case reflect.Complex128:
251
                return reflect.ValueOf(src.Complex())
252
253
        case reflect.String:
254
                return reflect.ValueOf(src.String())
255
        case reflect.Func:
256
                t := src.Type()
257
258
                if src.IsNil() {
259
                        return reflect.Zero(t)
260
                }
261
262
                // Don't use this trick unless we have no choice.
263
                return forceClearROFlag(src)
264
        case reflect.UnsafePointer:
265
                return reflect.ValueOf(unsafe.Pointer(src.Pointer()))
266
        }
267
268
        panic(fmt.Errorf("go-clone: <bug> impossible type `%v` when cloning private field", src.Type()))
269
}
func fixState.fixMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

593
func (fix *fixState) fixMap(v reflect.Value) (copied reflect.Value, changed int) {
594
        if v.IsNil() {
595
                return
596
        }
597
598
        t := v.Type()
599
        vst := visit{
600
                p: v.Pointer(),
601
                t: t,
602
        }
603
604
        if _, ok := fix.fixed[vst]; ok {
605
                return
606
        }
607
608
        fix.fixed[vst] = struct{}{}
609
610
        kt := t.Key()
611
        et := t.Elem()
612
        keyKind := kt.Kind()
613
        elemKind := et.Kind()
614
615
        if isScalar := fix.allocator.isScalar; isScalar(keyKind) && isScalar(elemKind) {
616
                return
617
        }
618
619
        invalidKeys := map[reflect.Value][2]reflect.Value{}
620
621
        for iter := mapIter(v); iter.Next(); {
622
                key := iter.Key()
623
                elem := iter.Value()
624
                var fixed reflect.Value
625
                c := 0
626
627
                if elemKind == reflect.Ptr {
628
                        vst := visit{
629
                                p: elem.Pointer(),
630
                                t: et,
631
                        }
632
633
                        if nv, ok := fix.invalid[vst]; ok {
634
                                fixed = nv
635
                                c++
636
                        } else {
637
                                fixed, c = fix.fixPtr(elem)
638
                        }
639
                } else {
640
                        fixed, c = fix.fix(elem)
641
                }
642
643
                changed += c
644
                c = 0
645
646
                if fixed.IsValid() {
647
                        v = forceSetMapIndex(v, key, fixed)
648
                        elem = fixed
649
                        fixed = reflect.Value{}
650
                }
651
652
                if keyKind == reflect.Ptr {
653
                        vst := visit{
654
                                p: key.Pointer(),
655
                                t: kt,
656
                        }
657
658
                        if nv, ok := fix.invalid[vst]; ok {
659
                                fixed = nv
660
                                c++
661
                        } else {
662
                                fixed, c = fix.fixPtr(key)
663
                        }
664
                } else {
665
                        fixed, c = fix.fix(key)
666
                }
667
668
                changed += c
669
670
                // Key cannot be changed immediately inside map range iteration.
671
                // Do it later.
672
                if fixed.IsValid() {
673
                        invalidKeys[key] = [2]reflect.Value{fixed, elem}
674
                }
675
        }
676
677
        for key, kv := range invalidKeys {
678
                v = forceSetMapIndex(v, key, reflect.Value{})
679
                v = forceSetMapIndex(v, kv[0], kv[1])
680
        }
681
682
        return
683
}
func fixState.fixStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

788
func (fix *fixState) fixStruct(v reflect.Value) (copied reflect.Value, changed int) {
789
        t := v.Type()
790
        st := fix.allocator.loadStructType(t)
791
792
        if len(st.PointerFields) == 0 {
793
                return
794
        }
795
796
        for _, pf := range st.PointerFields {
797
                i := int(pf.Index)
798
                field := v.Field(i)
799
800
                ft := field.Type()
801
802
                if ft.Kind() == reflect.Ptr {
803
                        vst := visit{
804
                                p: field.Pointer(),
805
                                t: ft,
806
                        }
807
808
                        if nv, ok := fix.invalid[vst]; ok {
809
                                // If v is not addressable, a new struct must be allocated.
810
                                // Don't do it unless there is no other choices.
811
                                if !v.CanAddr() {
812
                                        copied = fix.new(t).Elem()
813
                                        shadowCopy(v, unsafe.Pointer(copied.Addr().Pointer()))
814
                                        _, changed = fix.fixStruct(copied)
815
                                        return
816
                                }
817
818
                                ptr := unsafe.Pointer(v.Addr().Pointer())
819
                                p := unsafe.Pointer(uintptr(ptr) + pf.Offset)
820
                                shadowCopy(nv, p)
821
                                continue
822
                        }
823
                }
824
825
                fixed, c := fix.fix(field)
826
                changed += c
827
828
                if fixed.IsValid() {
829
                        // If v is not addressable, a new struct must be allocated.
830
                        // Don't do it unless there is no other choices.
831
                        if !v.CanAddr() {
832
                                copied = fix.new(t).Elem()
833
                                shadowCopy(v, unsafe.Pointer(copied.Addr().Pointer()))
834
                                _, changed = fix.fixStruct(copied)
835
                                return
836
                        }
837
838
                        ptr := unsafe.Pointer(v.Addr().Pointer())
839
                        p := unsafe.Pointer(uintptr(ptr) + pf.Offset)
840
                        shadowCopy(fixed, p)
841
                }
842
        }
843
844
        return
845
}
func fixState.fixArray
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

506
func (fix *fixState) fixArray(v reflect.Value) (copied reflect.Value, changed int) {
507
        t := v.Type()
508
        et := t.Elem()
509
        kind := et.Kind()
510
511
        if fix.allocator.isScalar(kind) {
512
                return
513
        }
514
515
        l := v.Len()
516
517
        for i := 0; i < l; i++ {
518
                elem := v.Index(i)
519
520
                if kind == reflect.Ptr {
521
                        vst := visit{
522
                                p: elem.Pointer(),
523
                                t: et,
524
                        }
525
526
                        if nv, ok := fix.invalid[vst]; ok {
527
                                // If elem cannot be set, v must be copied to make it settable.
528
                                // Don't do it unless there is no other choices.
529
                                if !elem.CanSet() {
530
                                        copied = fix.new(t).Elem()
531
                                        shadowCopy(v, unsafe.Pointer(copied.Addr().Pointer()))
532
                                        _, changed = fix.fixArray(copied)
533
                                        return
534
                                }
535
536
                                elem.Set(nv)
537
                                changed++
538
                                continue
539
                        }
540
                }
541
542
                fixed, c := fix.fix(elem)
543
                changed += c
544
545
                if fixed.IsValid() {
546
                        // If elem cannot be set, v must be copied to make it settable.
547
                        // Don't do it unless there is no other choices.
548
                        if !elem.CanSet() {
549
                                copied = fix.new(t).Elem()
550
                                shadowCopy(v, unsafe.Pointer(copied.Addr().Pointer()))
551
                                _, changed = fix.fixArray(copied)
552
                                return
553
                        }
554
555
                        elem.Set(fixed)
556
                }
557
        }
558
559
        return
560
}
func fixState.fixSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

729
func (fix *fixState) fixSlice(v reflect.Value) (copied reflect.Value, changed int) {
730
        if v.IsNil() {
731
                return
732
        }
733
734
        t := v.Type()
735
        et := t.Elem()
736
        kind := et.Kind()
737
738
        if fix.allocator.isScalar(kind) {
739
                return
740
        }
741
742
        l := v.Len()
743
        p := unsafe.Pointer(v.Pointer())
744
        vst := visit{
745
                p:     uintptr(p),
746
                extra: l,
747
                t:     t,
748
        }
749
750
        if _, ok := fix.fixed[vst]; ok {
751
                return
752
        }
753
754
        fix.fixed[vst] = struct{}{}
755
756
        for i := 0; i < l; i++ {
757
                elem := v.Index(i)
758
                var fixed reflect.Value
759
                c := 0
760
761
                if kind == reflect.Ptr {
762
                        vst := visit{
763
                                p: elem.Pointer(),
764
                                t: et,
765
                        }
766
767
                        if nv, ok := fix.invalid[vst]; ok {
768
                                fixed = nv
769
                        } else {
770
                                fixed, c = fix.fixPtr(elem)
771
                        }
772
                } else {
773
                        fixed, c = fix.fix(elem)
774
                }
775
776
                changed += c
777
778
                if fixed.IsValid() {
779
                        sz := et.Size()
780
                        elemPtr := unsafe.Pointer(uintptr(p) + sz*uintptr(i))
781
                        shadowCopy(fixed, elemPtr)
782
                }
783
        }
784
785
        return
786
}
func wrap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

35
func wrap(v interface{}) interface{} {
36
        if v == nil {
37
                return v
38
        }
39
40
        val := reflect.ValueOf(v)
41
        pt := val.Type()
42
43
        if val.Kind() != reflect.Ptr {
44
                return v
45
        }
46
47
        t := pt.Elem()
48
        elem := val.Elem()
49
        ptr := unsafe.Pointer(val.Pointer())
50
        cache, ok := cachedWrapperTypes.Load(t)
51
52
        if !ok {
53
                cache = reflect.StructOf([]reflect.StructField{
54
                        {
55
                                Name:      "T",
56
                                Type:      t,
57
                                Anonymous: true,
58
                        },
59
                        {
60
                                Name: "Checksum",
61
                                Type: reflect.TypeOf(uint64(0)),
62
                        },
63
                        {
64
                                Name: "Origin",
65
                                Type: pt,
66
                        },
67
                })
68
                cachedWrapperTypes.Store(t, cache)
69
        }
70
71
        wrapperType := cache.(reflect.Type)
72
        pw := defaultAllocator.New(wrapperType)
73
74
        wrapperPtr := unsafe.Pointer(pw.Pointer())
75
        wrapper := pw.Elem()
76
77
        // Equivalent code: wrapper.T = Clone(v)
78
        field := wrapper.Field(0)
79
        field.Set(heapCloneState.clone(elem))
80
81
        // Equivalent code: wrapper.Checksum = makeChecksum(v)
82
        checksumPtr := unsafe.Pointer(uintptr(wrapperPtr) + t.Size())
83
        *(*uint64)(checksumPtr) = makeChecksum(t, uintptr(wrapperPtr), uintptr(ptr))
84
85
        // Equivalent code: wrapper.Origin = v
86
        originPtr := unsafe.Pointer(uintptr(wrapperPtr) + t.Size() + sizeOfChecksum)
87
        *(*uintptr)(originPtr) = uintptr(ptr)
88
89
        return field.Addr().Interface()
90
}
func newAllocator
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

54
func newAllocator(pool unsafe.Pointer, methods *AllocatorMethods) (allocator *Allocator) {
55
        parent := methods.parent()
56
        new := methods.new(parent, pool)
57
58
        // Allocate the allocator from the pool.
59
        val := new(pool, typeOfAllocator)
60
        allocator = (*Allocator)(unsafe.Pointer(val.Pointer()))
61
        runtime.KeepAlive(val)
62
63
        allocator.pool = pool
64
        allocator.new = new
65
        allocator.makeSlice = methods.makeSlice(parent, pool)
66
        allocator.makeMap = methods.makeMap(parent, pool)
67
        allocator.makeChan = methods.makeChan(parent, pool)
68
        allocator.isScalar = methods.isScalar(parent)
69
70
        if parent == nil {
71
                parent = defaultAllocator
72
        }
73
74
        allocator.parent = parent
75
        return
76
}
func fixState.fixInterface
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

562
func (fix *fixState) fixInterface(v reflect.Value) (copied reflect.Value, changed int) {
563
        if v.IsNil() {
564
                return
565
        }
566
567
        elem := v.Elem()
568
        t := elem.Type()
569
        kind := elem.Kind()
570
571
        if kind == reflect.Ptr {
572
                vst := visit{
573
                        p: elem.Pointer(),
574
                        t: t,
575
                }
576
577
                if nv, ok := fix.invalid[vst]; ok {
578
                        copied = nv.Convert(v.Type())
579
                        changed++
580
                        return
581
                }
582
        }
583
584
        copied, changed = fix.fix(elem)
585
586
        if copied.IsValid() {
587
                copied = copied.Convert(v.Type())
588
        }
589
590
        return
591
}
func fixState.fix
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

477
func (fix *fixState) fix(v reflect.Value) (copied reflect.Value, changed int) {
478
        if fix.allocator.isScalar(v.Kind()) {
479
                return
480
        }
481
482
        switch v.Kind() {
483
        case reflect.Array:
484
                return fix.fixArray(v)
485
        case reflect.Chan:
486
                // Do nothing.
487
                return
488
        case reflect.Interface:
489
                return fix.fixInterface(v)
490
        case reflect.Map:
491
                return fix.fixMap(v)
492
        case reflect.Ptr:
493
                return fix.fixPtr(v)
494
        case reflect.Slice:
495
                return fix.fixSlice(v)
496
        case reflect.Struct:
497
                return fix.fixStruct(v)
498
        case reflect.String:
499
                // Do nothing.
500
                return
501
        default:
502
                panic(fmt.Errorf("go-clone: <bug> unsupported type `%v`", v.Type()))
503
        }
504
}
func fixState.fixPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

704
func (fix *fixState) fixPtr(v reflect.Value) (copied reflect.Value, changed int) {
705
        if v.IsNil() {
706
                return
707
        }
708
709
        vst := visit{
710
                p: v.Pointer(),
711
                t: v.Type(),
712
        }
713
714
        if _, ok := fix.invalid[vst]; ok {
715
                panic(fmt.Errorf("go-clone: <bug> invalid pointers must have been fixed in other methods"))
716
        }
717
718
        if _, ok := fix.fixed[vst]; ok {
719
                return
720
        }
721
722
        fix.fixed[vst] = struct{}{}
723
724
        elem := v.Elem()
725
        _, changed = fix.fix(elem)
726
        return
727
}
func cloneState.cloneString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

275
func (state *cloneState) cloneString(v reflect.Value) reflect.Value {
276
        t := v.Type()
277
        l := v.Len()
278
        data := state.allocator.MakeSlice(typeOfByteSlice, l, l)
279
280
        // The v is an unexported struct field.
281
        if !v.CanInterface() {
282
                v = reflect.ValueOf(v.String())
283
        }
284
285
        reflect.Copy(data, v)
286
287
        nv := state.allocator.New(t)
288
        slice := data.Interface().([]byte)
289
        *(*stringHeader)(unsafe.Pointer(nv.Pointer())) = *(*stringHeader)(unsafe.Pointer(&slice))
290
291
        return nv.Elem()
292
}
func forceSetMapIndex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

685
func forceSetMapIndex(v, key, elem reflect.Value) (nv reflect.Value) {
686
        nv = v
687
688
        if !v.CanInterface() {
689
                nv = forceClearROFlag(v)
690
        }
691
692
        if !key.CanInterface() {
693
                key = forceClearROFlag(key)
694
        }
695
696
        if elem.IsValid() && !elem.CanInterface() {
697
                elem = forceClearROFlag(elem)
698
        }
699
700
        nv.SetMapIndex(key, elem)
701
        return
702
}
func undo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

140
func undo(v interface{}) {
141
        if v == nil {
142
                return
143
        }
144
145
        val := reflect.ValueOf(v)
146
147
        if !isWrapped(val) {
148
                return
149
        }
150
151
        origVal := origin(val)
152
        elem := val.Elem()
153
        elem.Set(heapCloneState.clone(origVal.Elem()))
154
}
func AllocatorMethods.makeChan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

87
func (am *AllocatorMethods) makeChan(parent *Allocator, pool unsafe.Pointer) func(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value {
88
        if am != nil && am.MakeChan != nil {
89
                return am.MakeChan
90
        }
91
92
        if parent != nil {
93
                if parent.pool == pool {
94
                        return parent.makeChan
95
                } else {
96
                        return func(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value {
97
                                return parent.MakeChan(t, buffer)
98
                        }
99
                }
100
        }
101
102
        return defaultAllocator.makeChan
103
}
func @90:48
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

90
func(allocator *Allocator, old, new reflect.Value) {
91
                if !old.CanAddr() {
92
                        return
93
                }
94
95
                // Clone value inside atomic.Value.
96
                oldValue := old.Addr().Interface().(*atomic.Value)
97
                newValue := new.Addr().Interface().(*atomic.Value)
98
                v := oldValue.Load()
99
                cloned := clone(allocator, v)
100
                newValue.Store(cloned)
101
        }
func AllocatorMethods.new
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

33
func (am *AllocatorMethods) new(parent *Allocator, pool unsafe.Pointer) func(pool unsafe.Pointer, t reflect.Type) reflect.Value {
34
        if am != nil && am.New != nil {
35
                return am.New
36
        }
37
38
        if parent != nil {
39
                if parent.pool == pool {
40
                        return parent.new
41
                } else {
42
                        return func(pool unsafe.Pointer, t reflect.Type) reflect.Value {
43
                                return parent.New(t)
44
                        }
45
                }
46
        }
47
48
        return defaultAllocator.new
49
}
func unwrap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

114
func unwrap(v interface{}) interface{} {
115
        if v == nil {
116
                return v
117
        }
118
119
        val := reflect.ValueOf(v)
120
121
        if !isWrapped(val) {
122
                return v
123
        }
124
125
        origVal := origin(val)
126
        return origVal.Interface()
127
}
func AllocatorMethods.makeMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

69
func (am *AllocatorMethods) makeMap(parent *Allocator, pool unsafe.Pointer) func(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value {
70
        if am != nil && am.MakeMap != nil {
71
                return am.MakeMap
72
        }
73
74
        if parent != nil {
75
                if parent.pool == pool {
76
                        return parent.makeMap
77
                } else {
78
                        return func(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value {
79
                                return parent.MakeMap(t, n)
80
                        }
81
                }
82
        }
83
84
        return defaultAllocator.makeMap
85
}
func AllocatorMethods.makeSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

51
func (am *AllocatorMethods) makeSlice(parent *Allocator, pool unsafe.Pointer) func(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value {
52
        if am != nil && am.MakeSlice != nil {
53
                return am.MakeSlice
54
        }
55
56
        if parent != nil {
57
                if parent.pool == pool {
58
                        return parent.makeSlice
59
                } else {
60
                        return func(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value {
61
                                return parent.MakeSlice(t, len, cap)
62
                        }
63
                }
64
        }
65
66
        return defaultAllocator.makeSlice
67
}
func isWrapped
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

156
func isWrapped(val reflect.Value) bool {
157
        pt := val.Type()
158
159
        if pt.Kind() != reflect.Ptr {
160
                return false
161
        }
162
163
        t := pt.Elem()
164
        ptr := unsafe.Pointer(val.Pointer())
165
        return validateChecksum(t, ptr)
166
}
func origin
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

129
func origin(val reflect.Value) reflect.Value {
130
        pt := val.Type()
131
        t := pt.Elem()
132
        ptr := unsafe.Pointer(val.Pointer())
133
        orig := getOrigin(t, ptr)
134
        origVal := reflect.NewAt(t, orig)
135
        return origVal
136
}
func Map
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

94
func Map[T Clonable[T], K comparable](s map[K]T) (d map[K]T) {
95
        if s == nil {
96
                return
97
        }
98
        d = make(map[K]T, len(s))
99
        for k, v := range s {
100
                d[k] = v.Clone()
101
        }
102
        return
103
}
func Slice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

83
func Slice[T Clonable[T], TS ~[]T](s TS) (d TS) {
84
        if s == nil {
85
                return
86
        }
87
        d = make(TS, 0, len(s))
88
        for _, item := range s {
89
                d = append(d, item.Clone())
90
        }
91
        return
92
}
func @75:44
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

75
func(allocator *Allocator, old, new reflect.Value) {
76
                if !old.CanAddr() {
77
                        return
78
                }
79
80
                // Clone all values inside sync.Map.
81
                oldMap := old.Addr().Interface().(*sync.Map)
82
                newMap := new.Addr().Interface().(*sync.Map)
83
                oldMap.Range(func(key, value interface{}) bool {
84
                        k := clone(allocator, key)
85
                        v := clone(allocator, value)
86
                        newMap.Store(k, v)
87
                        return true
88
                })
89
        }
func DecimalPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

55
func DecimalPtr(s *decimal.Decimal) (d *decimal.Decimal) {
56
        if s == nil {
57
                return
58
        }
59
        d = new(decimal.Decimal)
60
        *d = s.Copy()
61
        return
62
}
func ComparablePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

10
func ComparablePtr[T comparable](s *T) (d *T) {
11
        if s == nil {
12
                return
13
        }
14
        d = new(T)
15
        *d = *s
16
        return
17
}
func AllocatorMethods.isScalar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

105
func (am *AllocatorMethods) isScalar(parent *Allocator) func(t reflect.Kind) bool {
106
        if am != nil && am.IsScalar != nil {
107
                return am.IsScalar
108
        }
109
110
        if parent != nil {
111
                return parent.isScalar
112
        }
113
114
        return defaultAllocator.isScalar
115
}
func validateChecksum
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

92
func validateChecksum(t reflect.Type, ptr unsafe.Pointer) bool {
93
        pw := uintptr(ptr)
94
        orig := uintptr(getOrigin(t, ptr))
95
        checksum := *(*uint64)(unsafe.Pointer(uintptr(ptr) + t.Size()))
96
        expected := makeChecksum(t, pw, orig)
97
98
        return checksum == expected
99
}
func SliceComparablePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

28
func SliceComparablePtr[T comparable, TS ~[]*T](s TS) (d TS) {
29
        if s == nil {
30
                return
31
        }
32
        d = make(TS, len(s), cap(s))
33
        copy(d, s)
34
        return
35
}
func TimePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

37
func TimePtr(s *time.Time) (d *time.Time) {
38
        if s == nil {
39
                return
40
        }
41
        d = new(time.Time)
42
        *d = time.Date(s.Year(), s.Month(), s.Day(), s.Hour(), s.Minute(), s.Second(), s.Nanosecond(),
43
                TimeLocationPtr(s.Location()))
44
        return
45
}
func makeChecksum
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

101
func makeChecksum(t reflect.Type, pw uintptr, orig uintptr) uint64 {
102
        var data [binary.MaxVarintLen64 * 2]byte
103
        binary.PutUvarint(data[:binary.MaxVarintLen64], uint64(pw))
104
        binary.PutUvarint(data[binary.MaxVarintLen64:], uint64(orig))
105
        return crc64.Checksum(data[:], crc64Table)
106
}
func TimeLocationPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

47
func TimeLocationPtr(s *time.Location) (d *time.Location) {
48
        if s == nil {
49
                return
50
        }
51
        d, _ = time.LoadLocation(s.String())
52
        return
53
}
func @83:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

83
func(key, value interface{}) bool {
84
                        k := clone(allocator, key)
85
                        v := clone(allocator, value)
86
                        newMap.Store(k, v)
87
                        return true
88
                }
func AllocatorMethods.parent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

25
func (am *AllocatorMethods) parent() *Allocator {
26
        if am != nil && am.Parent != nil {
27
                return am.Parent
28
        }
29
30
        return nil
31
}
func @69:45
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

69
func(allocator *Allocator, old, new reflect.Value) {
70
                // Copy the New func from old value.
71
                oldFn := old.FieldByName("New")
72
                newFn := allocator.Clone(oldFn)
73
                new.FieldByName("New").Set(newFn)
74
        }
func @63:45
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

63
func(allocator *Allocator, old, new reflect.Value) {
64
                // Copy the New func from old value.
65
                oldL := old.FieldByName("L")
66
                newL := allocator.Clone(oldL)
67
                new.FieldByName("L").Set(newL)
68
        }
func GormModelPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/base.go:

64
func GormModelPtr(s *gorm.Model) (d *gorm.Model) {
65
        if s == nil {
66
                return
67
        }
68
        return &gorm.Model{
69
                ID:        s.ID,
70
                CreatedAt: *TimePtr(&s.CreatedAt),
71
                UpdatedAt: *TimePtr(&s.UpdatedAt),
72
                DeletedAt: gorm.DeletedAt{
73
                        Time:  *TimePtr(&s.DeletedAt.Time),
74
                        Valid: s.DeletedAt.Valid,
75
                },
76
        }
77
}
func fixState.new
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/clone.go:

473
func (fix *fixState) new(t reflect.Type) reflect.Value {
474
        return fix.allocator.New(t)
475
}
func Undo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

64
func Undo[T any](t T) {
65
        undo(t)
66
}
func Unwrap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

58
func Unwrap[T any](t T) T {
59
        return unwrap(t).(T)
60
}
func heapMakeChan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

312
func heapMakeChan(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value {
313
        return reflect.MakeChan(t, buffer)
314
}
func Allocator.CloneSlowly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

121
func (a *Allocator) CloneSlowly(val reflect.Value) reflect.Value {
122
        return a.cloneSlowly(val, true)
123
}
func Allocator.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

99
func (a *Allocator) Clone(val reflect.Value) reflect.Value {
100
        return a.clone(val, true)
101
}
func Allocator.MakeChan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

94
func (a *Allocator) MakeChan(t reflect.Type, buffer int) reflect.Value {
95
        return a.makeChan(a.pool, t, buffer)
96
}
func NewAllocator
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

113
func NewAllocator(pool unsafe.Pointer, methods *AllocatorMethods) (allocator *Allocator) {
114
        return newAllocator(pool, methods)
115
}
func @42:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

42
func(pool unsafe.Pointer, t reflect.Type) reflect.Value {
43
                                return parent.New(t)
44
                        }
func Wrap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

52
func Wrap[T any](t T) T {
53
        return wrap(t).(T)
54
}
func @60:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

60
func(pool unsafe.Pointer, t reflect.Type, len, cap int) reflect.Value {
61
                                return parent.MakeSlice(t, len, cap)
62
                        }
func @78:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

78
func(pool unsafe.Pointer, t reflect.Type, n int) reflect.Value {
79
                                return parent.MakeMap(t, n)
80
                        }
func getOrigin
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/wrapper.go:

108
func getOrigin(t reflect.Type, ptr unsafe.Pointer) unsafe.Pointer {
109
        return *(*unsafe.Pointer)(unsafe.Pointer(uintptr(ptr) + t.Size() + sizeOfChecksum))
110
}
func @96:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocatormethods.go:

96
func(pool unsafe.Pointer, t reflect.Type, buffer int) reflect.Value {
97
                                return parent.MakeChan(t, buffer)
98
                        }
func FromHeap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/api_go118.go:

102
func FromHeap() *Allocator {
103
        return fromHeap()
104
}
func fromHeap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/allocator.go:

43
func fromHeap() *Allocator {
44
        return newAllocator(nil, nil)
45
}
func emptyCloneFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/clone/structtype.go:

138
func emptyCloneFunc(allocator *Allocator, old, new reflect.Value) {}
Package Overview: github.com/wfusion/gofusion/common/utils/cmp 23.1%

Please select a function to see what's left for testing.

MapAny(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 77.8% 7/9
SliceComparable(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 62.5% 5/8
ComparablePtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 60.0% 3/5
SliceAny(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 54.5% 6/11
anything(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 22.5% 9/40
deref(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 13.6% 3/22
Slice(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/11
Map(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/9
SliceComparablePtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/8
DecimalPtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/5
TimeLocationPtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/5
TimePtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/5
GormModelPtr(...) github.com/wfusion/gofusion/common/utils/cmp/base.go 0.0% 0/5
func MapAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

165
func MapAny[K comparable, T any](a, b map[K]T) bool {
166
        if a == nil && b == nil {
167
                return true
168
        }
169
        if a == nil || b == nil || len(a) != len(b) {
170
                return false
171
        }
172
173
        for ak, av := range a {
174
                bv, ok := b[ak]
175
                if !ok || !anything(av, bv) {
176
                        return false
177
                }
178
179
        }
180
        return true
181
}
func SliceComparable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

24
func SliceComparable[T comparable, TS ~[]T](a, b TS) bool {
25
        if a == nil && b == nil {
26
                return true
27
        }
28
        if a == nil || b == nil || len(a) != len(b) {
29
                return false
30
        }
31
        for i := 0; i < len(a); i++ {
32
                if a[i] != b[i] {
33
                        return false
34
                }
35
        }
36
        return true
37
}
func ComparablePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

14
func ComparablePtr[T comparable](a, b *T) bool {
15
        if a == nil && b == nil {
16
                return true
17
        }
18
        if a == nil || b == nil {
19
                return false
20
        }
21
22
        return *a == *b
23
}
func SliceAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

126
func SliceAny[T any, TS ~[]T](a, b TS, sortFn func(i, j T) int) bool {
127
        if a == nil && b == nil {
128
                return true
129
        }
130
        if a == nil || b == nil || len(a) != len(b) {
131
                return false
132
        }
133
134
        if sortFn != nil {
135
                utils.SortStable(a, sortFn)
136
                utils.SortStable(b, sortFn)
137
        }
138
139
        for i := 0; i < len(a); i++ {
140
                if !anything(a[i], b[i]) {
141
                        return false
142
                }
143
        }
144
        return true
145
}
func anything
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

183
func anything(a, b any) bool {
184
        switch av := a.(type) {
185
        case
186
                        bool,
187
                        string, uintptr,
188
                        int, int8, int16, int32, int64,
189
                        uint, uint8, uint16, uint32, uint64,
190
                        float32, float64,
191
                        complex64, complex128:
192
                return a == b
193
        case
194
                        *bool,
195
                        *string, *uintptr,
196
                        *int, *int8, *int16, *int32, *int64,
197
                        *uint, *uint8, *uint16, *uint32, *uint64,
198
                        *float32, *float64,
199
                        *complex64, *complex128:
200
                if a == nil && b == nil {
201
                        return true
202
                }
203
                if a == nil || b == nil {
204
                        return false
205
                }
206
                return anything(deref(a), deref(b))
207
        case decimal.Decimal:
208
                bv := b.(decimal.Decimal)
209
                return DecimalPtr(&av, &bv)
210
        case *decimal.Decimal:
211
                bv := b.(*decimal.Decimal)
212
                return DecimalPtr(av, bv)
213
        case time.Time:
214
                bv := b.(time.Time)
215
                return TimePtr(&av, &bv)
216
        case *time.Time:
217
                bv := b.(*time.Time)
218
                return TimePtr(av, bv)
219
        case time.Location:
220
                bv := b.(time.Location)
221
                return TimeLocationPtr(&av, &bv)
222
        case *time.Location:
223
                bv := b.(*time.Location)
224
                return TimeLocationPtr(av, bv)
225
        case []bool:
226
                return SliceComparable(a.([]bool), b.([]bool))
227
        case []string:
228
                return SliceComparable(a.([]string), b.([]string))
229
        case []uintptr:
230
                return SliceComparable(a.([]uintptr), b.([]uintptr))
231
        case []int:
232
                return SliceComparable(a.([]int), b.([]int))
233
        case []int8:
234
                return SliceComparable(a.([]int8), b.([]int8))
235
        case []int16:
236
                return SliceComparable(a.([]int16), b.([]int16))
237
        case []int32:
238
                return SliceComparable(a.([]int32), b.([]int32))
239
        case []int64:
240
                return SliceComparable(a.([]int64), b.([]int64))
241
        case []uint:
242
                return SliceComparable(a.([]uint), b.([]uint))
243
        case []uint8:
244
                return SliceComparable(a.([]uint8), b.([]uint8))
245
        case []uint16:
246
                return SliceComparable(a.([]uint16), b.([]uint16))
247
        case []uint32:
248
                return SliceComparable(a.([]uint32), b.([]uint32))
249
        case []uint64:
250
                return SliceComparable(a.([]uint64), b.([]uint64))
251
        case []float32:
252
                return SliceComparable(a.([]float32), b.([]float32))
253
        case []float64:
254
                return SliceComparable(a.([]float64), b.([]float64))
255
        case []complex64:
256
                return SliceComparable(a.([]complex64), b.([]complex64))
257
        case []complex128:
258
                return SliceComparable(a.([]complex128), b.([]complex128))
259
        case []any:
260
                return SliceAny(a.([]any), b.([]any), nil)
261
        case []map[string]any:
262
                return SliceAny(a.([]map[string]any), b.([]map[string]any), nil)
263
        case map[string]any:
264
                return MapAny(av, b.(map[string]any))
265
        default:
266
                return reflect.DeepEqual(a, b)
267
        }
268
}
func deref
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

270
func deref(p any) (v any) {
271
        switch pp := p.(type) {
272
        case *bool:
273
                v = *pp
274
        case *string:
275
                v = *pp
276
        case *int:
277
                v = *pp
278
        case *int8:
279
                v = *pp
280
        case *int16:
281
                v = *pp
282
        case *int32:
283
                v = *pp
284
        case *int64:
285
                v = *pp
286
        case *uint:
287
                v = *pp
288
        case *uint8:
289
                v = *pp
290
        case *uint16:
291
                v = *pp
292
        case *uint32:
293
                v = *pp
294
        case *uint64:
295
                v = *pp
296
        case *float32:
297
                v = *pp
298
        case *float64:
299
                v = *pp
300
        case *complex64:
301
                v = *pp
302
        case *complex128:
303
                v = *pp
304
        case *uintptr:
305
                v = *pp
306
        case *[]byte:
307
                v = *pp
308
        case *any:
309
                v = *pp
310
        default:
311
                panic(fmt.Errorf("unsupported type %T", pp))
312
        }
313
        return
314
}
func Slice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

105
func Slice[T _comparable[T], TS ~[]T](a, b TS, sortFn func(i, j T) int) bool {
106
        if a == nil && b == nil {
107
                return true
108
        }
109
        if a == nil || b == nil || len(a) != len(b) {
110
                return false
111
        }
112
113
        if sortFn != nil {
114
                utils.SortStable(a, sortFn)
115
                utils.SortStable(b, sortFn)
116
        }
117
118
        for i := 0; i < len(a); i++ {
119
                if !a[i].Equals(b[i]) {
120
                        return false
121
                }
122
        }
123
        return true
124
}
func Map
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

147
func Map[T _comparable[T], K comparable](a, b map[K]T) bool {
148
        if a == nil && b == nil {
149
                return true
150
        }
151
        if a == nil || b == nil || len(a) != len(b) {
152
                return false
153
        }
154
155
        for ak, av := range a {
156
                bv, ok := b[ak]
157
                if !ok || !av.Equals(bv) {
158
                        return false
159
                }
160
        }
161
162
        return true
163
}
func SliceComparablePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

38
func SliceComparablePtr[T comparable, TS ~[]*T](a, b TS) bool {
39
        if a == nil && b == nil {
40
                return true
41
        }
42
        if a == nil || b == nil || len(a) != len(b) {
43
                return false
44
        }
45
        for i := 0; i < len(a); i++ {
46
                if deref(a[i]) != deref(b[i]) {
47
                        return false
48
                }
49
        }
50
        return true
51
}
func DecimalPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

75
func DecimalPtr(a, b *decimal.Decimal) bool {
76
        if a == nil && b == nil {
77
                return true
78
        }
79
        if a == nil || b == nil {
80
                return false
81
        }
82
83
        return a.Equal(*b)
84
}
func TimeLocationPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

64
func TimeLocationPtr(a, b *time.Location) bool {
65
        if a == nil && b == nil {
66
                return true
67
        }
68
        if a == nil || b == nil {
69
                return false
70
        }
71
72
        return a.String() == b.String()
73
}
func TimePtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

53
func TimePtr(a, b *time.Time) bool {
54
        if a == nil && b == nil {
55
                return true
56
        }
57
        if a == nil || b == nil {
58
                return false
59
        }
60
61
        return a.Equal(*b) && TimeLocationPtr(a.Location(), b.Location())
62
}
func GormModelPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/cmp/base.go:

86
func GormModelPtr(a, b *gorm.Model) bool {
87
        if a == nil && b == nil {
88
                return true
89
        }
90
        if a == nil || b == nil {
91
                return false
92
        }
93
94
        return a.ID == b.ID &&
95
                TimePtr(&a.CreatedAt, &b.CreatedAt) &&
96
                TimePtr(&a.UpdatedAt, &b.UpdatedAt) &&
97
                a.DeletedAt.Valid == b.DeletedAt.Valid &&
98
                TimePtr(&a.DeletedAt.Time, &b.DeletedAt.Time)
99
}
Package Overview: github.com/wfusion/gofusion/common/utils/compress 73.7%

Please select a function to see what's left for testing.

@20:9(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 3/3
@31:24(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 3/3
@32:24(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 3/3
@21:9(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 3/3
decoder.Close(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 3/3
encoder.Close(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 3/3
@92:9(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 2/2
deflateDecodable.Reset(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 2/2
gzipDecodable.Reset(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 2/2
s2Decodable.Reset(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 2/2
encoder.Flush(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 2/2
zlibDecodable.Reset(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 2/2
@33:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
NewDecFunc(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 1/1
zlibDecodable.Read(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 1/1
Algorithm.String(...) github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go 100.0% 1/1
decoder.Read(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 1/1
deflateDecodable.Read(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 1/1
EncodeBytesFunc(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 1/1
Algorithm.IsValid(...) github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go 100.0% 1/1
gzipDecodable.Read(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 1/1
s2Decodable.Read(...) github.com/wfusion/gofusion/common/utils/compress/wrapper.go 100.0% 1/1
writerPoolSealer.Reset(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
readerPoolSealer.Reset(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@54:35(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@51:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@48:30(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
NewEncFunc(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 1/1
@45:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
encoder.Write(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 100.0% 1/1
@42:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
DecodeBytesFunc(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 100.0% 1/1
@36:35(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@24:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@27:32(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
@30:30(...) github.com/wfusion/gofusion/common/utils/compress/types.go 100.0% 1/1
Algorithm.Value(...) github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go 100.0% 1/1
@15:9(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 87.5% 14/16
ParseAlgorithm(...) github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go 83.3% 5/6
getDecoder(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 83.3% 5/6
getEncoder(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 83.3% 5/6
@103:9(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 75.0% 3/4
@16:9(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 73.7% 14/19
@61:9(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 0.0% 0/9
@54:9(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 0.0% 0/6
@69:9(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 0.0% 0/2
@59:9(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 0.0% 0/2
EncodeStreamFunc(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 0.0% 0/1
@66:27(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 0.0% 0/1
encoder.Reset(...) github.com/wfusion/gofusion/common/utils/compress/encode.go 0.0% 0/1
decoder.Reset(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 0.0% 0/1
@65:27(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 0.0% 0/1
DecodeStreamFunc(...) github.com/wfusion/gofusion/common/utils/compress/decode.go 0.0% 0/1
func @20:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

20
func() {
21
                        for _, cb := range recycles {
22
                                if cb != nil {
23
                                        cb()
24
                                }
25
                        }
26
                }
func @31:24
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

31
func() {
32
                        var cb func()
33
                        dec, cb = getDecoder(algo, srcBuffer)
34
                        recycles = append(recycles, cb)
35
                }
func @32:24
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

32
func() {
33
                        var cb func()
34
                        enc, cb = getEncoder(algo, dstBuffer)
35
                        recycles = append(recycles, cb)
36
                }
func @21:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

21
func() {
22
                        for _, cb := range recycles {
23
                                if cb != nil {
24
                                        cb()
25
                                }
26
                        }
27
                }
func decoder.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

104
func (e *decoder) Close() (err error)               { defer e.cb(); utils.CloseAnyway(e.r); return }
func encoder.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

119
func (e *encoder) Close() (err error) {
120
        defer e.cb()
121
        defer utils.CloseAnyway(e.w)
122
        return e.Flush()
123
}
func @92:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

92
func(r io.Reader) io.ReadCloser {
93
                dec, cb := getDecoder(algo, r)
94
                return &decoder{
95
                        dec: dec,
96
                        r:   r,
97
                        cb:  cb,
98
                }
99
        }
func deflateDecodable.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

31
func (d *deflateDecodable) Reset(r io.Reader) (err error)    { d.ReadCloser = flate.NewReader(r); return }
func gzipDecodable.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

24
func (g *gzipDecodable) Reset(r io.Reader) (err error)    { g.ReadCloser, err = gzip.NewReader(r); return }
func s2Decodable.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

17
func (s *s2Decodable) Reset(r io.Reader) (err error)    { s.Reader.Reset(r); return }
func encoder.Flush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

118
func (e *encoder) Flush() (err error)                { defer utils.FlushAnyway(e.w); return e.enc.Flush() }
func zlibDecodable.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

38
func (z *zlibDecodable) Reset(r io.Reader) (err error)    { z.ReadCloser, err = zlib.NewReader(r); return }
func @33:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

33
func() *writerPoolSealer {
34
                        return &writerPoolSealer{gzip.NewWriter(nil)}
35
                }
func NewDecFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

91
func NewDecFunc(algo Algorithm) func(r io.Reader) io.ReadCloser {
92
        return func(r io.Reader) io.ReadCloser {
93
                dec, cb := getDecoder(algo, r)
94
                return &decoder{
95
                        dec: dec,
96
                        r:   r,
97
                        cb:  cb,
98
                }
99
        }
100
}
func zlibDecodable.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

37
func (z *zlibDecodable) Read(p []byte) (n int, err error) { return z.ReadCloser.Read(p) }
func Algorithm.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go:

37
func (e Algorithm) String() string {
38
        return algorithmEnum.String(e)
39
}
func decoder.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

103
func (e *decoder) Read(p []byte) (n int, err error) { return e.dec.Read(p) }
func deflateDecodable.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

30
func (d *deflateDecodable) Read(p []byte) (n int, err error) { return d.ReadCloser.Read(p) }
func EncodeBytesFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

15
func EncodeBytesFunc(algo Algorithm) func(src []byte) (dst []byte, err error) {
16
        return func(src []byte) (dst []byte, err error) {
17
                var (
18
                        enc      encodable
19
                        recycles []func()
20
                )
21
                defer func() {
22
                        for _, cb := range recycles {
23
                                if cb != nil {
24
                                        cb()
25
                                }
26
                        }
27
                }()
28
29
                dstBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
30
                recycles = append(recycles, bufferCb)
31
32
                _, err = utils.Catch(func() {
33
                        var cb func()
34
                        enc, cb = getEncoder(algo, dstBuffer)
35
                        recycles = append(recycles, cb)
36
                })
37
                if err != nil || enc == nil {
38
                        return
39
                }
40
41
                srcBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
42
                recycles = append(recycles, bufferCb)
43
                srcBuffer.Write(src)
44
                if _, err = io.Copy(enc, srcBuffer); err != nil {
45
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
46
                                return
47
                        }
48
                }
49
                if err = enc.Flush(); err != nil {
50
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
51
                                return
52
                        }
53
                }
54
                dst = make([]byte, dstBuffer.Len())
55
                copy(dst, dstBuffer.Bytes())
56
                return
57
        }
58
}
func Algorithm.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go:

41
func (e Algorithm) IsValid() bool {
42
        return algorithmEnum.IsValid(e)
43
}
func gzipDecodable.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

23
func (g *gzipDecodable) Read(p []byte) (n int, err error) { return g.ReadCloser.Read(p) }
func s2Decodable.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/wrapper.go:

16
func (s *s2Decodable) Read(p []byte) (n int, err error) { return s.Reader.Read(p) }
func writerPoolSealer.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

70
func (w *writerPoolSealer) Reset(obj any) {
71
        w.encodable.Reset(obj.(io.Writer))
72
}
func readerPoolSealer.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

64
func (r *readerPoolSealer) Reset(obj any) error {
65
        return r.decodable.Reset(obj.(io.Reader))
66
}
func @54:35
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

54
func() *readerPoolSealer {
55
                        return &readerPoolSealer{new(deflateDecodable)} // init when call reset method
56
                }
func @51:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

51
func() *readerPoolSealer {
52
                        return &readerPoolSealer{new(gzipDecodable)} // init when call reset method
53
                }
func @48:30
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

48
func() *readerPoolSealer {
49
                        return &readerPoolSealer{&s2Decodable{s2.NewReader(nil)}}
50
                }
func NewEncFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

102
func NewEncFunc(algo Algorithm) func(w io.Writer) encodable {
103
        return func(w io.Writer) encodable {
104
                enc, cb := getEncoder(algo, w)
105
                if enc == nil {
106
                        panic(ErrUnknownAlgorithm)
107
                }
108
                return &encoder{
109
                        enc: enc,
110
                        w:   w,
111
                        cb:  cb,
112
                }
113
        }
114
}
func @45:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

45
func() *readerPoolSealer {
46
                        return &readerPoolSealer{new(zlibDecodable)} // init when call reset method
47
                }
func encoder.Write
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

116
func (e *encoder) Write(p []byte) (n int, err error) { return e.enc.Write(p) }
func @42:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

42
func() *readerPoolSealer {
43
                        return &readerPoolSealer{utils.Must(zstd.NewReader(nil))}
44
                }
func DecodeBytesFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

14
func DecodeBytesFunc(algo Algorithm) func(src []byte) (dst []byte, err error) {
15
        return func(src []byte) (dst []byte, err error) {
16
                var (
17
                        dec      decodable
18
                        recycles []func()
19
                )
20
                defer func() {
21
                        for _, cb := range recycles {
22
                                if cb != nil {
23
                                        cb()
24
                                }
25
                        }
26
                }()
27
28
                srcBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
29
                recycles = append(recycles, bufferCb)
30
                srcBuffer.Write(src)
31
                _, err = utils.Catch(func() {
32
                        var cb func()
33
                        dec, cb = getDecoder(algo, srcBuffer)
34
                        recycles = append(recycles, cb)
35
                })
36
                if err != nil || dec == nil {
37
                        return
38
                }
39
40
                dstBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
41
                recycles = append(recycles, bufferCb)
42
                if _, err = io.Copy(dstBuffer, dec); err != nil {
43
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
44
                                return
45
                        }
46
                }
47
                dst = make([]byte, dstBuffer.Len())
48
                copy(dst, dstBuffer.Bytes())
49
                return
50
        }
51
}
func @36:35
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

36
func() *writerPoolSealer {
37
                        return &writerPoolSealer{utils.Must(flate.NewWriter(nil, flate.DefaultCompression))}
38
                }
func @24:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

24
func() *writerPoolSealer {
25
                        return &writerPoolSealer{utils.Must(zstd.NewWriter(nil))}
26
                }
func @27:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

27
func() *writerPoolSealer {
28
                        return &writerPoolSealer{zlib.NewWriter(nil)}
29
                }
func @30:30
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/types.go:

30
func() *writerPoolSealer {
31
                        return &writerPoolSealer{s2.NewWriter(nil)}
32
                }
func Algorithm.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go:

33
func (e Algorithm) Value() uint8 {
34
        return uint8(e)
35
}
func @15:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

15
func(src []byte) (dst []byte, err error) {
16
                var (
17
                        dec      decodable
18
                        recycles []func()
19
                )
20
                defer func() {
21
                        for _, cb := range recycles {
22
                                if cb != nil {
23
                                        cb()
24
                                }
25
                        }
26
                }()
27
28
                srcBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
29
                recycles = append(recycles, bufferCb)
30
                srcBuffer.Write(src)
31
                _, err = utils.Catch(func() {
32
                        var cb func()
33
                        dec, cb = getDecoder(algo, srcBuffer)
34
                        recycles = append(recycles, cb)
35
                })
36
                if err != nil || dec == nil {
37
                        return
38
                }
39
40
                dstBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
41
                recycles = append(recycles, bufferCb)
42
                if _, err = io.Copy(dstBuffer, dec); err != nil {
43
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
44
                                return
45
                        }
46
                }
47
                dst = make([]byte, dstBuffer.Len())
48
                copy(dst, dstBuffer.Bytes())
49
                return
50
        }
func ParseAlgorithm
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/algorithm_enum.go:

45
func ParseAlgorithm(s any) Algorithm {
46
        switch v := s.(type) {
47
        case string:
48
                if enumList := algorithmEnum.Enum(v); len(enumList) > 0 {
49
                        return enumList[0]
50
                }
51
        case Algorithm:
52
                return v
53
        default:
54
                return Algorithm(cast.ToInt(s))
55
        }
56
        return AlgorithmUnknown
57
}
func getDecoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

74
func getDecoder(algo Algorithm, src io.Reader) (dec decodable, recycle func()) {
75
        p, ok := decoderPools[algo]
76
        if !algo.IsValid() || !ok {
77
                panic(ErrUnknownAlgorithm)
78
        }
79
80
        sealer, recycle := p.Get(src)
81
        dec = sealer.decodable
82
        return
83
}
func getEncoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

85
func getEncoder(algo Algorithm, dst io.Writer) (enc encodable, recycle func()) {
86
        p, ok := encoderPools[algo]
87
        if !algo.IsValid() || !ok {
88
                panic(ErrUnknownAlgorithm)
89
        }
90
91
        sealer, recycle := p.Get(dst)
92
        enc = sealer.encodable
93
        return
94
}
func @103:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

103
func(w io.Writer) encodable {
104
                enc, cb := getEncoder(algo, w)
105
                if enc == nil {
106
                        panic(ErrUnknownAlgorithm)
107
                }
108
                return &encoder{
109
                        enc: enc,
110
                        w:   w,
111
                        cb:  cb,
112
                }
113
        }
func @16:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

16
func(src []byte) (dst []byte, err error) {
17
                var (
18
                        enc      encodable
19
                        recycles []func()
20
                )
21
                defer func() {
22
                        for _, cb := range recycles {
23
                                if cb != nil {
24
                                        cb()
25
                                }
26
                        }
27
                }()
28
29
                dstBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
30
                recycles = append(recycles, bufferCb)
31
32
                _, err = utils.Catch(func() {
33
                        var cb func()
34
                        enc, cb = getEncoder(algo, dstBuffer)
35
                        recycles = append(recycles, cb)
36
                })
37
                if err != nil || enc == nil {
38
                        return
39
                }
40
41
                srcBuffer, bufferCb := utils.BytesBufferPool.Get(nil)
42
                recycles = append(recycles, bufferCb)
43
                srcBuffer.Write(src)
44
                if _, err = io.Copy(enc, srcBuffer); err != nil {
45
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
46
                                return
47
                        }
48
                }
49
                if err = enc.Flush(); err != nil {
50
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
51
                                return
52
                        }
53
                }
54
                dst = make([]byte, dstBuffer.Len())
55
                copy(dst, dstBuffer.Bytes())
56
                return
57
        }
func @61:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

61
func(dst io.Writer, src io.Reader) (err error) {
62
                var (
63
                        enc encodable
64
                        cb  func()
65
                )
66
                if _, err = utils.Catch(func() { enc, cb = getEncoder(algo, dst) }); err != nil {
67
                        return
68
                }
69
                defer func() {
70
                        if cb != nil {
71
                                cb()
72
                        }
73
                }()
74
75
                if _, err = io.Copy(enc, src); err != nil {
76
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
77
                                return
78
                        }
79
                }
80
                err = enc.Flush()
81
                return utils.ErrIgnore(err, eofErrs...)
82
        }
func @54:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

54
func(dst io.Writer, src io.Reader) (err error) {
55
                var (
56
                        dec decodable
57
                        cb  func()
58
                )
59
                defer func() {
60
                        if cb != nil {
61
                                cb()
62
                        }
63
                }()
64
65
                if _, err = utils.Catch(func() { dec, cb = getDecoder(algo, src) }); err != nil {
66
                        return
67
                }
68
69
                _, err = io.Copy(dst, dec)
70
                return utils.ErrIgnore(err, eofErrs...)
71
        }
func @69:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

69
func() {
70
                        if cb != nil {
71
                                cb()
72
                        }
73
                }
func @59:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

59
func() {
60
                        if cb != nil {
61
                                cb()
62
                        }
63
                }
func EncodeStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

60
func EncodeStreamFunc(algo Algorithm) func(dst io.Writer, src io.Reader) (err error) {
61
        return func(dst io.Writer, src io.Reader) (err error) {
62
                var (
63
                        enc encodable
64
                        cb  func()
65
                )
66
                if _, err = utils.Catch(func() { enc, cb = getEncoder(algo, dst) }); err != nil {
67
                        return
68
                }
69
                defer func() {
70
                        if cb != nil {
71
                                cb()
72
                        }
73
                }()
74
75
                if _, err = io.Copy(enc, src); err != nil {
76
                        if err = utils.ErrIgnore(err, eofErrs...); err != nil {
77
                                return
78
                        }
79
                }
80
                err = enc.Flush()
81
                return utils.ErrIgnore(err, eofErrs...)
82
        }
83
}
func @66:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

66
func() { enc, cb = getEncoder(algo, dst) }
func encoder.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/encode.go:

117
func (e *encoder) Reset(w io.Writer)                 { e.enc.Reset(w) }
func decoder.Reset
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

102
func (e *decoder) Reset(r io.Reader) error          { return e.dec.Reset(r) }
func @65:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

65
func() { dec, cb = getDecoder(algo, src) }
func DecodeStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/compress/decode.go:

53
func DecodeStreamFunc(algo Algorithm) func(dst io.Writer, src io.Reader) (err error) {
54
        return func(dst io.Writer, src io.Reader) (err error) {
55
                var (
56
                        dec decodable
57
                        cb  func()
58
                )
59
                defer func() {
60
                        if cb != nil {
61
                                cb()
62
                        }
63
                }()
64
65
                if _, err = utils.Catch(func() { dec, cb = getDecoder(algo, src) }); err != nil {
66
                        return
67
                }
68
69
                _, err = io.Copy(dst, dec)
70
                return utils.ErrIgnore(err, eofErrs...)
71
        }
72
}
Package Overview: github.com/wfusion/gofusion/common/utils/encode 84.3%

Please select a function to see what's left for testing.

codecStream.Decode(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 12/12
@193:9(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 5/5
@46:9(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 4/4
codec.Decode(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 100.0% 4/4
codec.Encode(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 100.0% 4/4
@133:9(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 3/3
decoder.Close(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 2/2
encoder.Close(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 2/2
Cipher(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 1/1
Compress(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 1/1
@38:26(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 100.0% 1/1
@55:9(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 1/1
encoder.Write(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 1/1
newEncoder(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 1/1
Encode(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 1/1
EncodedType.IsValid(...) github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go 100.0% 1/1
decoder.Read(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 1/1
newDecoder(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 1/1
Algorithm.IsValid(...) github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go 100.0% 1/1
Algorithm.String(...) github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go 100.0% 1/1
@109:16(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 100.0% 1/1
@61:9(...) github.com/wfusion/gofusion/common/utils/encode/types.go 100.0% 1/1
NewEncodeFunc(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 94.4% 17/18
NewDecodeFunc(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 94.4% 17/18
codecStream.Encode(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 91.7% 11/12
NewWriter(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 88.9% 8/9
From(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 87.5% 7/8
NewCodecStream(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 85.7% 6/7
parseEncodedType(...) github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go 83.3% 5/6
NewReader(...) github.com/wfusion/gofusion/common/utils/encode/stream.go 80.0% 8/10
codec.ToBytes(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 80.0% 4/5
codec.decode(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 78.6% 11/14
codec.encode(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 78.6% 11/14
codec.transform(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 75.0% 6/8
codec.ToString(...) github.com/wfusion/gofusion/common/utils/encode/codec.go 75.0% 3/4
ParseAlgorithm(...) github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go 50.0% 3/6
ParseEncodedType(...) github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go 0.0% 0/6
EncodedType.Value(...) github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go 0.0% 0/1
EncodedType.String(...) github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go 0.0% 0/1
Algorithm.Value(...) github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go 0.0% 0/1
func codecStream.Decode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

59
func (w *codecStream) Decode(dst io.Writer, src io.Reader) (n int64, err error) {
60
        for i := len(w.encodeOrder) - 1; i >= 0; i-- {
61
                switch w.encodeOrder[i] {
62
                case EncodedTypeCompress:
63
                        src = compress.NewDecFunc(w.o.compressAlgo)(src)
64
                case EncodedTypeCipher:
65
                        src = cipher.NewDecFunc(w.o.cipherAlgo, w.o.cipherMode, w.o.key, w.o.iv)(src)
66
                case EncodedTypeEncode:
67
                        src = NewReader(w.o.printableAlgo, src)
68
                }
69
        }
70
71
        buf, cb := utils.BytesPool.Get(defaultBufferSize)
72
        defer cb()
73
        defer utils.CloseAnyway(src)
74
        n, err = io.CopyBuffer(dst, src, buf)
75
        if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
76
                err = nil
77
        }
78
        return
79
}
func @193:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

193
func(src []byte) (dst []byte, err error) {
194
                dst = make([]byte, decodedLenFunc(len(src)))
195
                n, err := decodeFunc(dst, src)
196
                if err == nil {
197
                        dst = dst[:n]
198
                }
199
                return
200
        }
func @46:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

46
func(o *option) {
47
                o.cipherAlgo = algo
48
                o.cipherMode = mode
49
                o.key = clone.SliceComparable(key)
50
                o.iv = clone.SliceComparable(iv)
51
        }
func codec.Decode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

49
func (c *codec) Decode(opts ...utils.OptionExtender) Codecable {
50
        for i, p := 0, len(c.decOpts); i < len(opts); i++ {
51
                c.queue = append(c.queue, [2]int{p + i, 1})
52
        }
53
        c.decOpts = append(c.decOpts, opts...)
54
        return c
55
}
func codec.Encode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

42
func (c *codec) Encode(opts ...utils.OptionExtender) Codecable {
43
        for i, p := 0, len(c.encOpts); i < len(opts); i++ {
44
                c.queue = append(c.queue, [2]int{p + i, 0})
45
        }
46
        c.encOpts = append(c.encOpts, opts...)
47
        return c
48
}
func @133:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

133
func(src []byte) (dst []byte, err error) {
134
                dst = make([]byte, encodedLenFunc(len(src)))
135
                encodeFunc(dst, src)
136
                return
137
        }
func decoder.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

212
func (e *decoder) Close()                           { utils.CloseAnyway(e.r); utils.CloseAnyway(e.dec) }
func encoder.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

223
func (e *encoder) Close()                            { utils.CloseAnyway(e.enc); utils.CloseAnyway(e.w) }
func Cipher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

45
func Cipher(algo cipher.Algorithm, mode cipher.Mode, key, iv []byte) utils.OptionFunc[option] {
46
        return func(o *option) {
47
                o.cipherAlgo = algo
48
                o.cipherMode = mode
49
                o.key = clone.SliceComparable(key)
50
                o.iv = clone.SliceComparable(iv)
51
        }
52
}
func Compress
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

54
func Compress(algo compress.Algorithm) utils.OptionFunc[option] {
55
        return func(o *option) {
56
                o.compressAlgo = algo
57
        }
58
}
func @38:26
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

38
func(c *codec) { c.release() }
func @55:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

55
func(o *option) {
56
                o.compressAlgo = algo
57
        }
func encoder.Write
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

222
func (e *encoder) Write(p []byte) (n int, err error) { return e.enc.Write(p) }
func newEncoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

218
func newEncoder(enc, w io.Writer) io.Writer {
219
        return &encoder{enc: enc, w: w}
220
}
func Encode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

60
func Encode(algo Algorithm) utils.OptionFunc[option] {
61
        return func(o *option) {
62
                o.printableAlgo = algo
63
        }
64
}
func EncodedType.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go:

36
func (e EncodedType) IsValid() bool {
37
        return encodeTypeEnum.IsValid(e)
38
}
func decoder.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

211
func (e *decoder) Read(p []byte) (n int, err error) { return e.dec.Read(p) }
func newDecoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

207
func newDecoder(dec, r io.Reader) io.Reader {
208
        return &decoder{dec: dec, r: r}
209
}
func Algorithm.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go:

45
func (e Algorithm) IsValid() bool {
46
        return algorithmEnum.IsValid(e)
47
}
func Algorithm.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go:

41
func (e Algorithm) String() string {
42
        return algorithmEnum.String(e)
43
}
func @109:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

109
func(src, dst []byte) { hex.Encode(src, dst) }
func @61:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/types.go:

61
func(o *option) {
62
                o.printableAlgo = algo
63
        }
func NewEncodeFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

102
func NewEncodeFunc(algo Algorithm) func([]byte) ([]byte, error) {
103
        var (
104
                encodeFunc     func(src, dst []byte)
105
                encodedLenFunc func(int) int
106
        )
107
        switch algo {
108
        case AlgorithmHex:
109
                encodeFunc = func(src, dst []byte) { hex.Encode(src, dst) }
110
                encodedLenFunc = hex.EncodedLen
111
        case AlgorithmBase32Std:
112
                encodeFunc = base32.StdEncoding.Encode
113
                encodedLenFunc = base32.StdEncoding.EncodedLen
114
        case AlgorithmBase32Hex:
115
                encodeFunc = base32.HexEncoding.Encode
116
                encodedLenFunc = base32.HexEncoding.EncodedLen
117
        case AlgorithmBase64Std:
118
                encodeFunc = base64.StdEncoding.Encode
119
                encodedLenFunc = base64.StdEncoding.EncodedLen
120
        case AlgorithmBase64URL:
121
                encodeFunc = base64.URLEncoding.Encode
122
                encodedLenFunc = base64.URLEncoding.EncodedLen
123
        case AlgorithmBase64RawStd:
124
                encodeFunc = base64.RawStdEncoding.Encode
125
                encodedLenFunc = base64.RawStdEncoding.EncodedLen
126
        case AlgorithmBase64RawURL:
127
                encodeFunc = base64.RawURLEncoding.Encode
128
                encodedLenFunc = base64.RawURLEncoding.EncodedLen
129
        default:
130
                panic(ErrUnknownAlgorithm)
131
        }
132
133
        return func(src []byte) (dst []byte, err error) {
134
                dst = make([]byte, encodedLenFunc(len(src)))
135
                encodeFunc(dst, src)
136
                return
137
        }
138
}
func NewDecodeFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

162
func NewDecodeFunc(algo Algorithm) func([]byte) ([]byte, error) {
163
        var (
164
                decodeFunc     func(src, dst []byte) (int, error)
165
                decodedLenFunc func(int) int
166
        )
167
        switch algo {
168
        case AlgorithmHex:
169
                decodeFunc = hex.Decode
170
                decodedLenFunc = hex.DecodedLen
171
        case AlgorithmBase32Std:
172
                decodeFunc = base32.StdEncoding.Decode
173
                decodedLenFunc = base32.StdEncoding.DecodedLen
174
        case AlgorithmBase32Hex:
175
                decodeFunc = base32.HexEncoding.Decode
176
                decodedLenFunc = base32.HexEncoding.DecodedLen
177
        case AlgorithmBase64Std:
178
                decodeFunc = base64.StdEncoding.Decode
179
                decodedLenFunc = base64.StdEncoding.DecodedLen
180
        case AlgorithmBase64URL:
181
                decodeFunc = base64.URLEncoding.Decode
182
                decodedLenFunc = base64.URLEncoding.DecodedLen
183
        case AlgorithmBase64RawStd:
184
                decodeFunc = base64.RawStdEncoding.Decode
185
                decodedLenFunc = base64.RawStdEncoding.DecodedLen
186
        case AlgorithmBase64RawURL:
187
                decodeFunc = base64.RawURLEncoding.Decode
188
                decodedLenFunc = base64.RawURLEncoding.DecodedLen
189
        default:
190
                panic(ErrUnknownAlgorithm)
191
        }
192
193
        return func(src []byte) (dst []byte, err error) {
194
                dst = make([]byte, decodedLenFunc(len(src)))
195
                n, err := decodeFunc(dst, src)
196
                if err == nil {
197
                        dst = dst[:n]
198
                }
199
                return
200
        }
201
}
func codecStream.Encode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

36
func (w *codecStream) Encode(dst io.Writer, src io.Reader) (n int64, err error) {
37
        for i := len(w.encodeOrder) - 1; i >= 0; i-- {
38
                switch w.encodeOrder[i] {
39
                case EncodedTypeCompress:
40
                        dst = compress.NewEncFunc(w.o.compressAlgo)(dst)
41
                case EncodedTypeCipher:
42
                        dst = cipher.NewEncFunc(w.o.cipherAlgo, w.o.cipherMode, w.o.key, w.o.iv)(dst)
43
                case EncodedTypeEncode:
44
                        dst = NewWriter(w.o.printableAlgo, dst)
45
                }
46
        }
47
48
        buf, cb := utils.BytesPool.Get(defaultBufferSize)
49
        defer cb()
50
51
        defer utils.CloseAnyway(dst)
52
        n, err = io.CopyBuffer(dst, src, buf)
53
        if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
54
                err = nil
55
        }
56
        return
57
}
func NewWriter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

81
func NewWriter(algo Algorithm, w io.Writer) io.Writer {
82
        switch algo {
83
        case AlgorithmHex:
84
                return newEncoder(hex.NewEncoder(w), w)
85
        case AlgorithmBase32Std:
86
                return newEncoder(base32.NewEncoder(base32.StdEncoding, w), w)
87
        case AlgorithmBase32Hex:
88
                return newEncoder(base32.NewEncoder(base32.HexEncoding, w), w)
89
        case AlgorithmBase64Std:
90
                return newEncoder(base64.NewEncoder(base64.StdEncoding, w), w)
91
        case AlgorithmBase64URL:
92
                return newEncoder(base64.NewEncoder(base64.URLEncoding, w), w)
93
        case AlgorithmBase64RawStd:
94
                return newEncoder(base64.NewEncoder(base64.RawStdEncoding, w), w)
95
        case AlgorithmBase64RawURL:
96
                return newEncoder(base64.NewEncoder(base64.RawURLEncoding, w), w)
97
        default:
98
                panic(ErrUnknownAlgorithm)
99
        }
100
}
func From
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

21
func From[T ~[]byte | ~string](src T) (c Codecable) {
22
        buf, cb := utils.BytesBufferPool.Get(nil)
23
24
        switch v := any(src).(type) {
25
        case []byte:
26
                buf.Write(v)
27
        case string:
28
                buf.WriteString(v)
29
        default:
30
                buf.Write([]byte(src))
31
        }
32
33
        c = &codec{
34
                buf:     buf,
35
                release: cb,
36
        }
37
38
        runtime.SetFinalizer(c, func(c *codec) { c.release() })
39
        return
40
}
func NewCodecStream
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

15
func NewCodecStream(opts ...utils.OptionExtender) Streamable {
16
        encodeOrder := make([]EncodedType, 0, len(opts))
17
        for _, opt := range opts {
18
                if encType := parseEncodedType(opt); encType.IsValid() {
19
                        encodeOrder = append(encodeOrder, encType)
20
                }
21
        }
22
        if len(encodeOrder) == 0 {
23
                panic(ErrEncodeMethodNotFound)
24
        }
25
        return &codecStream{
26
                o:           utils.ApplyOptions[option](opts...),
27
                encodeOrder: encodeOrder,
28
        }
29
}
func parseEncodedType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go:

54
func parseEncodedType(one utils.OptionExtender) EncodedType {
55
        opts := utils.ApplyOptions[option](one)
56
        switch {
57
        case opts.cipherAlgo.IsValid():
58
                return EncodedTypeCipher
59
        case opts.compressAlgo.IsValid():
60
                return EncodedTypeCompress
61
        case opts.printableAlgo.IsValid():
62
                return EncodedTypeEncode
63
        default:
64
                return EncodedTypeUnknown
65
        }
66
}
func NewReader
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/stream.go:

140
func NewReader(algo Algorithm, r io.Reader) io.Reader {
141
        switch algo {
142
        case AlgorithmHex:
143
                return newDecoder(hex.NewDecoder(r), r)
144
        case AlgorithmBase32Std:
145
                return newDecoder(base32.NewDecoder(base32.StdEncoding, r), r)
146
        case AlgorithmBase32Hex:
147
                return newDecoder(base32.NewDecoder(base32.HexEncoding, r), r)
148
        case AlgorithmBase64Std:
149
                return newDecoder(base64.NewDecoder(base64.StdEncoding, r), r)
150
        case AlgorithmBase64URL:
151
                return newDecoder(base64.NewDecoder(base64.URLEncoding, r), r)
152
        case AlgorithmBase64RawStd:
153
                return newDecoder(base64.NewDecoder(base64.RawStdEncoding, r), r)
154
        case AlgorithmBase64RawURL:
155
                return newDecoder(base64.NewDecoder(base64.RawURLEncoding, r), r)
156
        default:
157
                panic(ErrUnknownAlgorithm)
158
        }
159
        return nil
160
}
func codec.ToBytes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

56
func (c *codec) ToBytes() (dst []byte, err error) {
57
        if err = c.transform(); err != nil {
58
                return
59
        }
60
        dst = make([]byte, c.buf.Len())
61
        copy(dst, c.buf.Bytes())
62
        return
63
}
func codec.decode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

114
func (c *codec) decode(opt utils.OptionExtender) (err error) {
115
        var dec func([]byte) ([]byte, error)
116
117
        switch option := utils.ApplyOptions[option](opt); parseEncodedType(opt) {
118
        case EncodedTypeCompress:
119
                dec = compress.DecodeBytesFunc(option.compressAlgo)
120
        case EncodedTypeCipher:
121
                dec, err = cipher.DecryptBytesFunc(option.cipherAlgo, option.cipherMode, option.key, option.iv)
122
        case EncodedTypeEncode:
123
                dec = NewDecodeFunc(option.printableAlgo)
124
        default:
125
                return ErrEncodeMethodNotFound
126
        }
127
        if err != nil {
128
                return
129
        }
130
131
        dst, err := dec(c.buf.Bytes())
132
        if err != nil {
133
                return
134
        }
135
        c.buf.Reset()
136
        c.buf.Write(dst)
137
        return
138
}
func codec.encode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

89
func (c *codec) encode(opt utils.OptionExtender) (err error) {
90
        var enc func([]byte) ([]byte, error)
91
92
        switch option := utils.ApplyOptions[option](opt); parseEncodedType(opt) {
93
        case EncodedTypeCompress:
94
                enc = compress.EncodeBytesFunc(option.compressAlgo)
95
        case EncodedTypeCipher:
96
                enc, err = cipher.EncryptBytesFunc(option.cipherAlgo, option.cipherMode, option.key, option.iv)
97
        case EncodedTypeEncode:
98
                enc = NewEncodeFunc(option.printableAlgo)
99
        default:
100
                return ErrEncodeMethodNotFound
101
        }
102
        if err != nil {
103
                return
104
        }
105
106
        dst, err := enc(c.buf.Bytes())
107
        if err != nil {
108
                return
109
        }
110
        c.buf.Reset()
111
        c.buf.Write(dst)
112
        return
113
}
func codec.transform
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

72
func (c *codec) transform() (err error) {
73
        for _, elem := range c.queue {
74
                idx, isEnc := elem[0], elem[1] == 0
75
                if isEnc {
76
                        if err = c.encode(c.encOpts[idx]); err != nil {
77
                                return
78
                        }
79
                } else {
80
                        if err = c.decode(c.decOpts[idx]); err != nil {
81
                                return
82
                        }
83
84
                }
85
        }
86
87
        return
88
}
func codec.ToString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/codec.go:

64
func (c *codec) ToString() (dst string, err error) {
65
        if err = c.transform(); err != nil {
66
                return
67
        }
68
        dst = c.buf.String()
69
        return
70
}
func ParseAlgorithm
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go:

49
func ParseAlgorithm(s any) Algorithm {
50
        switch v := s.(type) {
51
        case string:
52
                if enumList := algorithmEnum.Enum(v); len(enumList) > 0 {
53
                        return enumList[0]
54
                }
55
        case Algorithm:
56
                return v
57
        default:
58
                return Algorithm(cast.ToInt(s))
59
        }
60
        return AlgorithmUnknown
61
}
func ParseEncodedType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go:

40
func ParseEncodedType(s any) EncodedType {
41
        switch v := s.(type) {
42
        case string:
43
                if enumList := encodeTypeEnum.Enum(v); len(enumList) > 0 {
44
                        return enumList[0]
45
                }
46
        case EncodedType:
47
                return v
48
        default:
49
                return EncodedType(cast.ToInt(s))
50
        }
51
        return EncodedTypeUnknown
52
}
func EncodedType.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go:

28
func (e EncodedType) Value() uint8 {
29
        return uint8(e)
30
}
func EncodedType.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/encode_type_enum.go:

32
func (e EncodedType) String() string {
33
        return encodeTypeEnum.String(e)
34
}
func Algorithm.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/encode/algorithm_enum.go:

37
func (e Algorithm) Value() uint8 {
38
        return uint8(e)
39
}
Package Overview: github.com/wfusion/gofusion/common/utils/inspect 67.7%

Please select a function to see what's left for testing.

@95:17(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 100.0% 5/5
init(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 100.0% 4/4
packType(...) github.com/wfusion/gofusion/common/utils/inspect/rtype.go 100.0% 3/3
Field.read(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 100.0% 3/3
Field.addr(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 100.0% 3/3
@106:17(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 100.0% 3/3
derefValue(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 100.0% 3/3
eface.pack(...) github.com/wfusion/gofusion/common/utils/inspect/rtype.go 100.0% 2/2
@71:14(...) github.com/wfusion/gofusion/common/utils/inspect/rtype.go 100.0% 2/2
GetField(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 100.0% 2/2
SetField(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 100.0% 1/1
newField(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 100.0% 1/1
unpackType(...) github.com/wfusion/gofusion/common/utils/inspect/rtype.go 100.0% 1/1
enumerateTypes(...) github.com/wfusion/gofusion/common/utils/inspect/init_go118.go 91.7% 11/12
enumerateFuncs(...) github.com/wfusion/gofusion/common/utils/inspect/init_go118.go 85.7% 6/7
TypeOf(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 80.0% 4/5
FuncOf(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 80.0% 4/5
Field.Set(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 75.0% 3/4
FieldByName(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 66.7% 2/3
mustOk(...) github.com/wfusion/gofusion/common/utils/inspect/misc_go118.go 66.7% 2/3
Field.Get(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 66.7% 2/3
@80:17(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 0.0% 0/4
@56:17(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 0.0% 0/4
getField(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 0.0% 0/3
FieldAt(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 0.0% 0/3
derefType(...) github.com/wfusion/gofusion/common/utils/inspect/field.go 0.0% 0/3
setField(...) github.com/wfusion/gofusion/common/utils/inspect/field_go118.go 0.0% 0/3
RuntimeFuncOf(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 0.0% 0/2
RuntimeTypeOf(...) github.com/wfusion/gofusion/common/utils/inspect/inspect.go 0.0% 0/2
func @95:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

95
func(typ reflect.Type) bool {
96
                pkgName := typ.PkgPath()
97
                typeName := typ.Name()
98
                if pkgName != "" && typeName != "" {
99
                        structs[pkgName+"."+typeName] = typ
100
                }
101
102
                return true
103
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

90
func init() {
91
        lock.Lock()
92
        defer lock.Unlock()
93
94
        // inspect structs
95
        enumerateTypes(func(typ reflect.Type) bool {
96
                pkgName := typ.PkgPath()
97
                typeName := typ.Name()
98
                if pkgName != "" && typeName != "" {
99
                        structs[pkgName+"."+typeName] = typ
100
                }
101
102
                return true
103
        })
104
105
        // inspect function
106
        enumerateFuncs(func(fn *runtime.Func, addr uintptr) bool {
107
                if funcName := fn.Name(); funcName != "" {
108
                        funcs[funcName] = unsafe.Pointer(&addr)
109
                }
110
                return true
111
        })
112
}
func packType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/rtype.go:

81
func packType(t *rtype) (r reflect.Type) {
82
        (*iface)(unsafe.Pointer(&r)).tab = itabRtype
83
        (*iface)(unsafe.Pointer(&r)).data = unsafe.Pointer(t)
84
        return
85
}
func Field.read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

34
func (f Field) read() eface {
35
        if ifaceIndir(f.t) {
36
                return eface{_type: f.t, data: f.p}
37
        } else {
38
                return eface{_type: f.t, data: *(*unsafe.Pointer)(f.p)}
39
        }
40
}
func Field.addr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

42
func (f Field) addr(v reflect.Value) unsafe.Pointer {
43
        if ifaceIndir(f.t) {
44
                return (*eface)(unsafe.Pointer(&v)).data
45
        } else {
46
                return unsafe.Pointer(&((*eface)(unsafe.Pointer(&v)).data))
47
        }
48
}
func @106:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

106
func(fn *runtime.Func, addr uintptr) bool {
107
                if funcName := fn.Name(); funcName != "" {
108
                        funcs[funcName] = unsafe.Pointer(&addr)
109
                }
110
                return true
111
        }
func derefValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

64
func derefValue(t reflect.Value) reflect.Value {
65
        for t.Kind() == reflect.Ptr {
66
                t = t.Elem()
67
        }
68
        return t
69
}
func eface.pack
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/rtype.go:

25
func (e eface) pack() (r interface{}) { *(*eface)(unsafe.Pointer(&r)) = e; return }
func @71:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/rtype.go:

71
func(v interface{}) *itab {
72
                t := reflect.TypeOf(v).Elem()
73
                return (*iface)(unsafe.Pointer(&t)).tab
74
        }
func GetField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

35
func GetField[T any](obj any, fieldName string) (r T) {
36
        r, _ = mustOk(FieldByName(derefValue(reflect.ValueOf(obj)), fieldName)).Get().Interface().(T)
37
        return
38
}
func SetField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

31
func SetField[T any](obj any, fieldName string, val T) {
32
        mustOk(FieldByName(derefValue(reflect.ValueOf(obj)), fieldName)).Set(reflect.ValueOf(val))
33
}
func newField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

50
func newField(v reflect.Value, fv reflect.StructField) Field {
51
        return Field{
52
                t: unpackType(fv.Type),
53
                p: unsafe.Pointer(uintptr((*eface)(unsafe.Pointer(&v)).data) + fv.Offset),
54
        }
55
}
func unpackType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/rtype.go:

77
func unpackType(t reflect.Type) *rtype {
78
        return (*rtype)((*eface)(unsafe.Pointer(&t)).data)
79
}
func enumerateTypes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/init_go118.go:

12
func enumerateTypes(cb func(reflect.Type) bool) {
13
        t0 := reflect.TypeOf(struct{}{})
14
        sections, typeLinks := typelinks()
15
        for i, typeLink := range typeLinks {
16
                for _, link := range typeLink {
17
                        (*eface)(unsafe.Pointer(&t0)).data = resolveTypeOff(sections[i], link)
18
                        if t0.Kind() != reflect.Ptr || !supportTypes[t0.Elem().Kind()] {
19
                                continue
20
                        }
21
                        typ := t0.Elem()
22
                        if typ.PkgPath() == "" || typ.Name() == "" {
23
                                continue
24
                        }
25
                        if !cb(typ) {
26
                                return
27
                        }
28
                }
29
        }
30
}
func enumerateFuncs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/init_go118.go:

32
func enumerateFuncs(cb func(*runtime.Func, uintptr) bool) {
33
        for _, md := range activeModules() {
34
                for _, tab := range md.ftab {
35
                        f := tab // should not take from &tab.entry because go syntax
36
                        absoluteAddr := textAddr(md, f.entry)
37
                        if fn := runtime.FuncForPC(absoluteAddr); fn != nil {
38
                                if !cb(fn, absoluteAddr) {
39
                                        return
40
                                }
41
                        }
42
                }
43
        }
44
}
func TypeOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

45
func TypeOf(typeName string) reflect.Type {
46
        lock.RLock()
47
        defer lock.RUnlock()
48
        if typ, ok := structs[typeName]; ok {
49
                return typ
50
        }
51
        return nil
52
}
func FuncOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

68
func FuncOf(funcName string) unsafe.Pointer {
69
        lock.RLock()
70
        defer lock.RUnlock()
71
        if entry, ok := funcs[funcName]; ok {
72
                return unsafe.Pointer(&entry)
73
        }
74
        return nil
75
}
func Field.Set
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

25
func (f Field) Set(v reflect.Value) {
26
        if f.t == nil {
27
                panic(errors.New("inspect: invalid field"))
28
        }
29
30
        v = v.Convert(packType(f.t))
31
        typedmemmove(f.t, f.p, f.addr(v))
32
}
func FieldByName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

14
func FieldByName(v reflect.Value, name string) (Field, bool) {
15
        if fv, ok := v.Type().FieldByName(name); !ok {
16
                return Field{}, false
17
        } else {
18
                return newField(v, fv), true
19
        }
20
}
func mustOk
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/misc_go118.go:

8
func mustOk[T any](out T, ok bool) T {
9
        if !ok {
10
                panic(errors.Errorf("get %T with ok is false", out))
11
        }
12
        return out
13
}
func Field.Get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

17
func (f Field) Get() reflect.Value {
18
        if f.t == nil {
19
                panic(errors.New("inspect: invalid field"))
20
        }
21
        return reflect.ValueOf(f.read().pack())
22
}
func @80:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

80
func(fn *runtime.Func, addr uintptr) bool {
81
                if fn.Name() == funcName {
82
                        r = unsafe.Pointer(&addr)
83
                        return false
84
                }
85
                return true
86
        }
func @56:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

56
func(typ reflect.Type) bool {
57
                if typ.PkgPath()+"."+typ.Name() == typeName {
58
                        r = typ
59
                        return false
60
                }
61
                return true
62
        }
func getField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

48
func getField[T any](obj any, fieldName string) (r T) {
49
        v := reflect.Indirect(reflect.ValueOf(obj))
50
        r, _ = valueInterface(v.FieldByName(fieldName), false).(T)
51
        return
52
}
func FieldAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

23
func FieldAt(v reflect.Value, idx int) (Field, bool) {
24
        if idx < 0 || idx >= v.NumField() {
25
                return Field{}, false
26
        } else {
27
                return newField(v, v.Type().Field(idx)), true
28
        }
29
}
func derefType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field.go:

57
func derefType(t reflect.Type) reflect.Type {
58
        for t.Kind() == reflect.Ptr {
59
                t = t.Elem()
60
        }
61
        return t
62
}
func setField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/field_go118.go:

41
func setField[T any](obj any, fieldName string, val T) {
42
        v := reflect.ValueOf(obj)
43
        t := reflect.Indirect(v).Type()
44
        *(*T)(unsafe.Pointer(v.Pointer() + mustOk(t.FieldByName(fieldName)).Offset)) = val
45
}
func RuntimeFuncOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

79
func RuntimeFuncOf(funcName string) (r unsafe.Pointer) {
80
        enumerateFuncs(func(fn *runtime.Func, addr uintptr) bool {
81
                if fn.Name() == funcName {
82
                        r = unsafe.Pointer(&addr)
83
                        return false
84
                }
85
                return true
86
        })
87
        return
88
}
func RuntimeTypeOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/inspect/inspect.go:

55
func RuntimeTypeOf(typeName string) (r reflect.Type) {
56
        enumerateTypes(func(typ reflect.Type) bool {
57
                if typ.PkgPath()+"."+typ.Name() == typeName {
58
                        r = typ
59
                        return false
60
                }
61
                return true
62
        })
63
        return
64
}
Package Overview: github.com/wfusion/gofusion/common/utils/serialize 66.7%

Please select a function to see what's left for testing.

@17:9(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 100.0% 5/5
@19:18(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 5/5
@27:21(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 4/4
@52:21(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 3/3
@55:9(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 100.0% 2/2
@57:18(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
Algorithm.Value(...) github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go 100.0% 1/1
@36:9(...) github.com/wfusion/gofusion/common/utils/serialize/marshal.go 100.0% 1/1
@16:17(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
Algorithm.IsValid(...) github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go 100.0% 1/1
Algorithm.String(...) github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go 100.0% 1/1
@33:18(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
@39:17(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
@83:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
JsonEscapeHTML(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 100.0% 1/1
@16:9(...) github.com/wfusion/gofusion/common/utils/serialize/marshal.go 85.7% 6/7
ParseAlgorithm(...) github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go 83.3% 5/6
UnmarshalStreamFunc(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 80.0% 4/5
MarshalFunc(...) github.com/wfusion/gofusion/common/utils/serialize/marshal.go 80.0% 4/5
UnmarshalFunc(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 80.0% 4/5
MarshalStreamFunc(...) github.com/wfusion/gofusion/common/utils/serialize/marshal.go 80.0% 4/5
@71:9(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 80.0% 4/5
UnmarshalStreamFuncByType(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 75.0% 6/8
@42:18(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 66.7% 4/6
UnmarshalFuncByType(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 0.0% 0/8
@37:9(...) github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go 0.0% 0/6
JsonIndent(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
@106:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
@77:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
@71:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
DisallowUnknownFields(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
@100:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
MsgpackUseCompactInts(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
JsonNumber(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
@89:9(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
MsgpackUseCompactFloats(...) github.com/wfusion/gofusion/common/utils/serialize/types.go 0.0% 0/1
func @17:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

17
func(src []byte) (dst T, err error) {
18
                bs, cb := utils.BytesBufferPool.Get(nil)
19
                defer cb()
20
21
                bs.Write(src)
22
                err = fn(&dst, bs, opt)
23
                return
24
        }
func @19:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

19
func(dst io.Writer, src any, opt *marshalOption) (err error) {
20
                        enc := json.NewEncoder(dst)
21
                        if !opt.jsonEscapeHTML {
22
                                enc.SetEscapeHTML(false)
23
                        }
24
                        enc.SetIndent(opt.jsonIndentPrefix, opt.jsonIndent)
25
                        return enc.Encode(src)
26
                }
func @27:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

27
func(dst io.Writer, src any, opt *marshalOption) (err error) {
28
                        enc := msgpack.NewEncoder(dst)
29
                        enc.UseCompactInts(opt.msgpackUseCompactInts)
30
                        enc.UseCompactFloats(opt.msgpackUseCompactFloats)
31
                        return enc.Encode(src)
32
                }
func @52:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

52
func(dst any, src io.Reader, opt *unmarshalOption) (err error) {
53
                        dec := msgpack.NewDecoder(src)
54
                        dec.DisallowUnknownFields(opt.disallowUnknownFields)
55
                        return dec.Decode(dst)
56
                }
func @55:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

55
func(src io.Reader) (dst T, err error) {
56
                err = fn(&dst, src, opt)
57
                return
58
        }
func @57:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

57
func(dst any, src io.Reader, opt *unmarshalOption) (err error) {
58
                        return cbor.NewDecoder(src).Decode(dst)
59
                }
func Algorithm.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go:

31
func (e Algorithm) Value() uint8 {
32
        return uint8(e)
33
}
func @36:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/marshal.go:

36
func(dst io.Writer, src any) error {
37
                return fn(dst, src, opt)
38
        }
func @16:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

16
func(dst io.Writer, src any, opt *marshalOption) (err error) {
17
                        return gob.NewEncoder(dst).Encode(src)
18
                }
func Algorithm.IsValid
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go:

39
func (e Algorithm) IsValid() bool {
40
        return algorithmEnum.IsValid(e)
41
}
func Algorithm.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go:

35
func (e Algorithm) String() string {
36
        return algorithmEnum.String(e)
37
}
func @33:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

33
func(dst io.Writer, src any, opt *marshalOption) (err error) {
34
                        return cbor.NewEncoder(dst).Encode(src)
35
                }
func @39:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

39
func(dst any, src io.Reader, opt *unmarshalOption) (err error) {
40
                        return gob.NewDecoder(src).Decode(dst)
41
                }
func @83:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

83
func(o *marshalOption) {
84
                o.jsonEscapeHTML = on
85
        }
func JsonEscapeHTML
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

82
func JsonEscapeHTML(on bool) utils.OptionFunc[marshalOption] {
83
        return func(o *marshalOption) {
84
                o.jsonEscapeHTML = on
85
        }
86
}
func @16:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/marshal.go:

16
func(src any) (dst []byte, err error) {
17
                bs, cb := utils.BytesBufferPool.Get(nil)
18
                defer cb()
19
20
                if err = fn(bs, src, opt); err != nil {
21
                        return
22
                }
23
24
                dst = make([]byte, bs.Len())
25
                copy(dst, bs.Bytes())
26
                return
27
        }
func ParseAlgorithm
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/algorithm_enum.go:

43
func ParseAlgorithm(s any) Algorithm {
44
        switch v := s.(type) {
45
        case string:
46
                if enumList := algorithmEnum.Enum(v); len(enumList) > 0 {
47
                        return enumList[0]
48
                }
49
        case Algorithm:
50
                return v
51
        default:
52
                return Algorithm(cast.ToInt(s))
53
        }
54
        return AlgorithmUnknown
55
}
func UnmarshalStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

49
func UnmarshalStreamFunc[T any](algo Algorithm, opts ...utils.OptionExtender) func(io.Reader) (T, error) {
50
        fn, ok := unmarshalFuncMap[algo]
51
        if !ok {
52
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
53
        }
54
        opt := utils.ApplyOptions[unmarshalOption](opts...)
55
        return func(src io.Reader) (dst T, err error) {
56
                err = fn(&dst, src, opt)
57
                return
58
        }
59
}
func MarshalFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/marshal.go:

10
func MarshalFunc(algo Algorithm, opts ...utils.OptionExtender) func(src any) ([]byte, error) {
11
        fn, ok := marshalFuncMap[algo]
12
        if !ok {
13
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
14
        }
15
        opt := utils.ApplyOptions[marshalOption](opts...)
16
        return func(src any) (dst []byte, err error) {
17
                bs, cb := utils.BytesBufferPool.Get(nil)
18
                defer cb()
19
20
                if err = fn(bs, src, opt); err != nil {
21
                        return
22
                }
23
24
                dst = make([]byte, bs.Len())
25
                copy(dst, bs.Bytes())
26
                return
27
        }
28
}
func UnmarshalFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

11
func UnmarshalFunc[T any](algo Algorithm, opts ...utils.OptionExtender) func(src []byte) (T, error) {
12
        fn, ok := unmarshalFuncMap[algo]
13
        if !ok {
14
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
15
        }
16
        opt := utils.ApplyOptions[unmarshalOption](opts...)
17
        return func(src []byte) (dst T, err error) {
18
                bs, cb := utils.BytesBufferPool.Get(nil)
19
                defer cb()
20
21
                bs.Write(src)
22
                err = fn(&dst, bs, opt)
23
                return
24
        }
25
}
func MarshalStreamFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/marshal.go:

30
func MarshalStreamFunc(algo Algorithm, opts ...utils.OptionExtender) func(dst io.Writer, src any) error {
31
        fn, ok := marshalFuncMap[algo]
32
        if !ok {
33
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
34
        }
35
        opt := utils.ApplyOptions[marshalOption](opts...)
36
        return func(dst io.Writer, src any) error {
37
                return fn(dst, src, opt)
38
        }
39
}
func @71:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

71
func(src io.Reader) (dst any, err error) {
72
                d := reflect.New(dstType).Interface()
73
                if err = fn(d, src, opt); err != nil {
74
                        return
75
                }
76
                dst = reflect.Indirect(reflect.ValueOf(d)).Interface()
77
                return
78
        }
func UnmarshalStreamFuncByType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

61
func UnmarshalStreamFuncByType(algo Algorithm, dst any, opts ...utils.OptionExtender) func(io.Reader) (any, error) {
62
        fn, ok := unmarshalFuncMap[algo]
63
        if !ok {
64
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
65
        }
66
        dstType, ok := dst.(reflect.Type)
67
        if !ok {
68
                dstType = reflect.TypeOf(dst)
69
        }
70
        opt := utils.ApplyOptions[unmarshalOption](opts...)
71
        return func(src io.Reader) (dst any, err error) {
72
                d := reflect.New(dstType).Interface()
73
                if err = fn(d, src, opt); err != nil {
74
                        return
75
                }
76
                dst = reflect.Indirect(reflect.ValueOf(d)).Interface()
77
                return
78
        }
79
}
func @42:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

42
func(dst any, src io.Reader, opt *unmarshalOption) (err error) {
43
                        dec := json.NewDecoder(src)
44
                        if opt.jsonNumber {
45
                                dec.UseNumber()
46
                        }
47
                        if opt.disallowUnknownFields {
48
                                dec.DisallowUnknownFields()
49
                        }
50
                        return dec.Decode(dst)
51
                }
func UnmarshalFuncByType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

27
func UnmarshalFuncByType(algo Algorithm, dst any, opts ...utils.OptionExtender) func([]byte) (any, error) {
28
        fn, ok := unmarshalFuncMap[algo]
29
        if !ok {
30
                panic(fmt.Errorf("unknown serialize algorithm type %+v", algo))
31
        }
32
        dstType, ok := dst.(reflect.Type)
33
        if !ok {
34
                dstType = reflect.TypeOf(dst)
35
        }
36
        opt := utils.ApplyOptions[unmarshalOption](opts...)
37
        return func(src []byte) (dst any, err error) {
38
                dst = reflect.New(dstType).Interface()
39
40
                bs, cb := utils.BytesBufferPool.Get(nil)
41
                defer cb()
42
43
                bs.Write(src)
44
                err = fn(dst, bs, opt)
45
                return
46
        }
47
}
func @37:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/unmarshal.go:

37
func(src []byte) (dst any, err error) {
38
                dst = reflect.New(dstType).Interface()
39
40
                bs, cb := utils.BytesBufferPool.Get(nil)
41
                defer cb()
42
43
                bs.Write(src)
44
                err = fn(dst, bs, opt)
45
                return
46
        }
func JsonIndent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

88
func JsonIndent(prefix, indent string) utils.OptionFunc[marshalOption] {
89
        return func(o *marshalOption) {
90
                o.jsonIndentPrefix, o.jsonIndent = prefix, indent
91
        }
92
}
func @106:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

106
func(o *unmarshalOption) {
107
                o.disallowUnknownFields = true
108
        }
func @77:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

77
func(o *marshalOption) {
78
                o.msgpackUseCompactFloats = on
79
        }
func @71:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

71
func(o *marshalOption) {
72
                o.msgpackUseCompactInts = on
73
        }
func DisallowUnknownFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

105
func DisallowUnknownFields() utils.OptionFunc[unmarshalOption] {
106
        return func(o *unmarshalOption) {
107
                o.disallowUnknownFields = true
108
        }
109
}
func @100:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

100
func(o *unmarshalOption) {
101
                o.jsonNumber = true
102
        }
func MsgpackUseCompactInts
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

70
func MsgpackUseCompactInts(on bool) utils.OptionFunc[marshalOption] {
71
        return func(o *marshalOption) {
72
                o.msgpackUseCompactInts = on
73
        }
74
}
func JsonNumber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

99
func JsonNumber() utils.OptionFunc[unmarshalOption] {
100
        return func(o *unmarshalOption) {
101
                o.jsonNumber = true
102
        }
103
}
func @89:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

89
func(o *marshalOption) {
90
                o.jsonIndentPrefix, o.jsonIndent = prefix, indent
91
        }
func MsgpackUseCompactFloats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/common/utils/serialize/types.go:

76
func MsgpackUseCompactFloats(on bool) utils.OptionFunc[marshalOption] {
77
        return func(o *marshalOption) {
78
                o.msgpackUseCompactFloats = on
79
        }
80
}
Package Overview: github.com/wfusion/gofusion/config 79.5%

Please select a function to see what's left for testing.

registry.initComponents(...) github.com/wfusion/gofusion/config/registry.go 100.0% 21/21
@419:11(...) github.com/wfusion/gofusion/config/registry.go 100.0% 14/14
registry.initByConfigFile(...) github.com/wfusion/gofusion/config/registry.go 100.0% 12/12
registry.GetAllConfigs(...) github.com/wfusion/gofusion/config/registry.go 100.0% 12/12
@112:16(...) github.com/wfusion/gofusion/config/registry.go 100.0% 10/10
cryptoConf.cryptoConfuseKey(...) github.com/wfusion/gofusion/config/crypto.go 100.0% 10/10
registry.Init(...) github.com/wfusion/gofusion/config/registry.go 100.0% 9/9
New(...) github.com/wfusion/gofusion/config/registry.go 100.0% 7/7
registry.initAllConfigByLoadFunc(...) github.com/wfusion/gofusion/config/registry.go 100.0% 7/7
registry.makeAllConfigStruct(...) github.com/wfusion/gofusion/config/registry.go 100.0% 6/6
CryptoConstruct(...) github.com/wfusion/gofusion/config/crypto.go 100.0% 6/6
CryptoDecryptByTag(...) github.com/wfusion/gofusion/config/crypto.go 100.0% 6/6
registry.makeComponentsConfigFields(...) github.com/wfusion/gofusion/config/registry.go 100.0% 5/5
@355:26(...) github.com/wfusion/gofusion/config/registry.go 100.0% 5/5
registry.AppName(...) github.com/wfusion/gofusion/config/candy.go 100.0% 4/4
AddComponent(...) github.com/wfusion/gofusion/config/component.go 100.0% 4/4
registry.Debug(...) github.com/wfusion/gofusion/config/candy.go 100.0% 4/4
getComponents(...) github.com/wfusion/gofusion/config/component.go 100.0% 3/3
registry.makeComponentsConfigStruct(...) github.com/wfusion/gofusion/config/registry.go 100.0% 2/2
@96:9(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
DI(...) github.com/wfusion/gofusion/config/types.go 100.0% 1/1
@23:9(...) github.com/wfusion/gofusion/config/types.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/config/types.go 100.0% 1/1
WithTag(...) github.com/wfusion/gofusion/config/component.go 100.0% 1/1
@29:9(...) github.com/wfusion/gofusion/config/types.go 100.0% 1/1
registry.DI(...) github.com/wfusion/gofusion/config/candy.go 100.0% 1/1
@418:9(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
registry.getBaseObject(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
@361:34(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
registry.loadComponents(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
NewDefaultLoader(...) github.com/wfusion/gofusion/config/loader.go 100.0% 1/1
loader.Unmarshal(...) github.com/wfusion/gofusion/config/loader.go 100.0% 1/1
@40:23(...) github.com/wfusion/gofusion/config/loader.go 100.0% 1/1
@136:16(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
newOptions(...) github.com/wfusion/gofusion/config/component.go 100.0% 1/1
@357:32(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
@105:9(...) github.com/wfusion/gofusion/config/component.go 100.0% 1/1
Ctx(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
@84:9(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
Loader(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
@90:9(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
Files(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
@137:12(...) github.com/wfusion/gofusion/config/registry.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/config/loader.go 100.0% 1/1
@192:35(...) github.com/wfusion/gofusion/config/crypto.go 93.8% 15/16
registry.AddComponent(...) github.com/wfusion/gofusion/config/registry.go 93.1% 27/29
@36:18(...) github.com/wfusion/gofusion/config/candy.go 90.0% 9/10
Use(...) github.com/wfusion/gofusion/config/registry.go 83.3% 5/6
CryptoConf.ToOptionMap(...) github.com/wfusion/gofusion/config/crypto.go 83.3% 5/6
cryptoConf.ToOptions(...) github.com/wfusion/gofusion/config/crypto.go 81.8% 9/11
registry.cryptoConfig(...) github.com/wfusion/gofusion/config/candy.go 80.0% 8/10
loadConfig(...) github.com/wfusion/gofusion/config/loader.go 74.4% 29/39
registry.LoadComponentConfig(...) github.com/wfusion/gofusion/config/registry.go 71.4% 20/28
@452:37(...) github.com/wfusion/gofusion/config/registry.go 66.7% 6/9
registry.checkBusinessConfig(...) github.com/wfusion/gofusion/config/registry.go 66.7% 2/3
parseConstructor(...) github.com/wfusion/gofusion/config/component.go 60.0% 15/25
indexComponent(...) github.com/wfusion/gofusion/config/component.go 60.0% 3/5
checkCryptoConf(...) github.com/wfusion/gofusion/config/crypto.go 57.9% 11/19
registry.addComponent(...) github.com/wfusion/gofusion/config/registry.go 52.9% 9/17
@170:27(...) github.com/wfusion/gofusion/config/component.go 0.0% 0/8
CryptoDecryptFunc(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/7
CryptoEncryptFunc(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/5
@156:9(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/1
Component.Clone(...) github.com/wfusion/gofusion/config/component.go 0.0% 0/1
Debug(...) github.com/wfusion/gofusion/config/registry.go 0.0% 0/1
@166:9(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/1
@179:9(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/1
@112:9(...) github.com/wfusion/gofusion/config/component.go 0.0% 0/1
CryptoConfigName(...) github.com/wfusion/gofusion/config/crypto.go 0.0% 0/1
WithCore(...) github.com/wfusion/gofusion/config/component.go 0.0% 0/1
@102:9(...) github.com/wfusion/gofusion/config/registry.go 0.0% 0/1
@111:9(...) github.com/wfusion/gofusion/config/crypto.go 100.0% 0/0
func registry.initComponents
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

390
func (p *registry) initComponents(parent context.Context) func() {
391
        ctx, cancel := context.WithCancel(parent)
392
        ctxVal := reflect.ValueOf(ctx)
393
        o1 := reflect.ValueOf(utils.OptionExtender(AppName(p.appName)))
394
        o2 := reflect.ValueOf(utils.OptionExtender(DI(p.di)))
395
396
        baseObject := p.getBaseObject()
397
        destructors := make([]reflect.Value, 0, len(p.componentList))
398
        componentNames := make([]string, 0, len(p.componentList))
399
        hasCallbackComponentNames := make([]string, 0, len(p.componentList))
400
        for i := 0; i < len(p.componentList); i++ {
401
                com := p.componentList[i]
402
                comArgs := reflect.ValueOf(clone.Clone(baseObject.FieldByName(com.Name).Interface()))
403
                componentNames = append(componentNames, com.Name)
404
                if out := com.Constructor.Call([]reflect.Value{ctxVal, comArgs, o1, o2}); len(out) > 0 && !out[0].IsNil() {
405
                        destructors = append(destructors, out[0])
406
                        hasCallbackComponentNames = append(hasCallbackComponentNames, com.Name)
407
                }
408
        }
409
410
        /* print summary to stdout */
411
        pid := syscall.Getpid()
412
        app := p.AppName()
413
        log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds)
414
        log.Printf("%v [Gofusion] %s initialized total %d components below: %s\n",
415
                pid, app, len(componentNames), strings.Join(componentNames, ", "))
416
417
        once := new(sync.Once)
418
        return func() {
419
                once.Do(func() {
420
                        initLocker.Lock()
421
                        defer initLocker.Unlock()
422
423
                        defer close(p.closeCh)
424
425
                        p.initWg.Done()
426
                        p.initWg.Wait()
427
                        cancel()
428
                        for i := len(destructors) - 1; i >= 0; i-- {
429
                                log.Printf("%v [Gofusion] %s %s exiting...", pid, app, hasCallbackComponentNames[i])
430
                                destructors[i].Call(nil)
431
                                log.Printf("%v [Gofusion] %s %s exited", pid, app, hasCallbackComponentNames[i])
432
                        }
433
434
                        p.di.Clear()
435
                        p.businessConfig = nil
436
                        p.componentConfigs = nil
437
                        p.initOnce = new(sync.Once)
438
                })
439
        }
440
}
func @419:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

419
func() {
420
                        initLocker.Lock()
421
                        defer initLocker.Unlock()
422
423
                        defer close(p.closeCh)
424
425
                        p.initWg.Done()
426
                        p.initWg.Wait()
427
                        cancel()
428
                        for i := len(destructors) - 1; i >= 0; i-- {
429
                                log.Printf("%v [Gofusion] %s %s exiting...", pid, app, hasCallbackComponentNames[i])
430
                                destructors[i].Call(nil)
431
                                log.Printf("%v [Gofusion] %s %s exited", pid, app, hasCallbackComponentNames[i])
432
                        }
433
434
                        p.di.Clear()
435
                        p.businessConfig = nil
436
                        p.componentConfigs = nil
437
                        p.initOnce = new(sync.Once)
438
                }
func registry.initByConfigFile
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

266
func (p *registry) initByConfigFile(parent context.Context, businessConfig any,
267
        loadFn loadConfigFunc, opts ...utils.OptionExtender) func() {
268
        p.loadComponents()
269
        p.checkBusinessConfig(businessConfig)
270
        p.initAllConfigByLoadFunc(businessConfig, loadFn, opts...)
271
272
        appName := p.AppName()
273
        registryLock.Lock()
274
        if _, ok := registryMap[appName]; !ok {
275
                registryMap[appName] = p
276
        }
277
        registryLock.Unlock()
278
279
        // decrypt
280
        CryptoDecryptByTag(p.businessConfig, AppName(p.AppName()))
281
        CryptoDecryptByTag(p.componentConfigs, AppName(p.AppName()))
282
283
        // give back
284
        reflect.Indirect(reflect.ValueOf(businessConfig)).Set(reflect.ValueOf(p.businessConfig))
285
286
        return p.initComponents(parent)
287
}
func registry.GetAllConfigs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

245
func (p *registry) GetAllConfigs() any {
246
        val := reflect.New(p.makeAllConfigStruct())
247
        derefVal := reflect.Indirect(val)
248
249
        // business configs
250
        businessConfigsVal := reflect.Indirect(reflect.ValueOf(p.businessConfig))
251
        numFields := businessConfigsVal.NumField()
252
        for i := 0; i < numFields; i++ {
253
                derefVal.Field(i + 1).Set(businessConfigsVal.Field(i))
254
        }
255
256
        // component configs
257
        derefComponentConfigsVal := derefVal.FieldByName(componentConfigFieldName)
258
        componentConfigsVal := reflect.Indirect(reflect.ValueOf(p.componentConfigs)).FieldByName(componentConfigFieldName)
259
        numFields = componentConfigsVal.NumField()
260
        for i := 0; i < numFields; i++ {
261
                derefComponentConfigsVal.Field(i).Set(componentConfigsVal.Field(i))
262
        }
263
        return clone.Clone(val.Interface())
264
}
func @112:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

112
func() {
113
                opt := utils.ApplyOptions[initOption](opts...)
114
                p.debug = opt.debug
115
                p.closeCh = make(chan struct{})
116
117
                // context
118
                parent := context.Background()
119
                if opt.bizCtx != nil {
120
                        parent = opt.bizCtx
121
                }
122
123
                // load config function
124
                loadFn := loadConfig
125
                if opt.customLoadFunc != nil {
126
                        loadFn = opt.customLoadFunc
127
                }
128
129
                gracefully = p.initByConfigFile(parent, businessConfig, loadFn, opts...)
130
        }
func cryptoConf.cryptoConfuseKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

82
func (c *cryptoConf) cryptoConfuseKey(key []byte) (confused []byte) {
83
        var (
84
                k1 = make([]byte, len(key))
85
                k2 = make([]byte, len(key))
86
                k3 = make([]byte, len(key))
87
        )
88
        rndSeed := int64(crc64.Checksum(key, crc64.MakeTable(crc64.ISO)))
89
        utils.Must(rand.New(rand.NewSource(cipher.RndSeed ^ compress.RndSeed ^ rndSeed)).Read(k1))
90
        utils.Must(rand.New(rand.NewSource(cipher.RndSeed ^ encode.RndSeed ^ rndSeed)).Read(k2))
91
        utils.Must(rand.New(rand.NewSource(compress.RndSeed ^ encode.RndSeed ^ rndSeed)).Read(k3))
92
93
        confused = make([]byte, len(key))
94
        utils.Must(rand.New(rand.NewSource(cipher.RndSeed ^ compress.RndSeed ^ encode.RndSeed)).Read(confused))
95
        for i := 0; i < len(confused); i++ {
96
                confused[i] ^= k1[i] ^ k2[i] ^ k3[i]
97
        }
98
        return
99
}
func registry.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

107
func (p *registry) Init(businessConfig any, opts ...utils.OptionExtender) (gracefully func()) {
108
        initLocker.Lock()
109
        defer initLocker.Unlock()
110
111
        p.initWg.Add(1)
112
        p.initOnce.Do(func() {
113
                opt := utils.ApplyOptions[initOption](opts...)
114
                p.debug = opt.debug
115
                p.closeCh = make(chan struct{})
116
117
                // context
118
                parent := context.Background()
119
                if opt.bizCtx != nil {
120
                        parent = opt.bizCtx
121
                }
122
123
                // load config function
124
                loadFn := loadConfig
125
                if opt.customLoadFunc != nil {
126
                        loadFn = opt.customLoadFunc
127
                }
128
129
                gracefully = p.initByConfigFile(parent, businessConfig, loadFn, opts...)
130
        })
131
        if gracefully == nil {
132
                // give back
133
                reflect.Indirect(reflect.ValueOf(businessConfig)).Set(reflect.ValueOf(p.businessConfig))
134
135
                once := new(sync.Once)
136
                gracefully = func() {
137
                        once.Do(func() {
138
                                p.initWg.Done()
139
                        })
140
                }
141
        }
142
        return
143
}
func New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

44
func New(appName string) Configurable {
45
        registryLock.Lock()
46
        defer registryLock.Unlock()
47
        if reg, ok := registryMap[appName]; ok {
48
                return reg
49
        }
50
51
        reg := &registry{
52
                di:       di.NewDI(),
53
                appName:  appName,
54
                initOnce: new(sync.Once),
55
                closeCh:  make(chan struct{}),
56
        }
57
        registryMap[appName] = reg
58
        return reg
59
}
func registry.initAllConfigByLoadFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

378
func (p *registry) initAllConfigByLoadFunc(businessConfig any, loadFn loadConfigFunc, opts ...utils.OptionExtender) {
379
        businessConfigVal := reflect.ValueOf(businessConfig)
380
        p.businessConfigType = utils.IndirectType(businessConfigVal.Type())
381
382
        p.businessConfig = reflect.New(p.businessConfigType).Interface()
383
        p.componentConfigs = reflect.New(p.makeComponentsConfigStruct()).Interface()
384
        if loadFn != nil {
385
                loadFn(p.businessConfig, opts...)
386
                loadFn(p.componentConfigs, opts...)
387
        }
388
}
func registry.makeAllConfigStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

319
func (p *registry) makeAllConfigStruct() reflect.Type {
320
        /* AllConfig struct may look like below
321
        type AllConfig struct {
322
                XXXBase struct {
323
                        Debug       bool
324
                        App         string
325
                        DB          map[string]*db.Conf
326
                        Redis       map[string]*redis.Conf
327
                        Log         *log.Conf
328
                        ...
329
                } `yaml:"base" json:"base" toml:"base"`
330
331
                BusinessConfigField1
332
            BusinessConfigField2
333
                BusinessConfigField3
334
335
                ...
336
        }
337
        */
338
339
        numFields := p.businessConfigType.NumField()
340
        fieldList := make([]reflect.StructField, 0, numFields+1)
341
        fieldList = append(fieldList, reflect.StructField{
342
                Name:      componentConfigFieldName,
343
                Type:      reflect.StructOf(p.makeComponentsConfigFields()),
344
                Tag:       `yaml:"base" json:"base" toml:"base"`,
345
                Anonymous: true,
346
        })
347
        for i := 0; i < numFields; i++ {
348
                fieldList = append(fieldList, p.businessConfigType.Field(i))
349
        }
350
351
        return reflect.StructOf(fieldList)
352
}
func CryptoConstruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

101
func CryptoConstruct(ctx context.Context, c CryptoConf, _ ...utils.OptionExtender) func() {
102
        if c.Config != nil {
103
                checkCryptoConf("", c.Config)
104
        }
105
        for name, cfg := range c.Custom {
106
                if cfg != nil {
107
                        checkCryptoConf(name, cfg)
108
                }
109
        }
110
111
        return func() {
112
113
        }
114
}
func CryptoDecryptByTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

184
func CryptoDecryptByTag(data any, opts ...utils.OptionExtender) {
185
        o := utils.ApplyOptions[InitOption](opts...)
186
        optsMap := Use(o.AppName).(*registry).cryptoConfig().ToOptionMap()
187
        for _, opts := range optsMap {
188
                utils.SliceReverse(opts)
189
        }
190
191
        supportedFields := utils.NewSet(reflect.Struct, reflect.Array, reflect.Slice, reflect.Map)
192
        utils.TraverseValue(data, false, func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
193
                if !value.IsValid() || !value.CanInterface() || !value.CanSet() {
194
                        return
195
                }
196
197
                vk := value.Kind()
198
                stepIn = supportedFields.Contains(vk) ||
199
                        (vk == reflect.Ptr && value.Elem().IsValid() && value.Elem().Kind() == reflect.Struct)
200
201
                configName, ok := field.Tag.Lookup(cryptoTagKey)
202
                if !ok {
203
                        return
204
                }
205
                opts, ok := optsMap[configName]
206
                if !ok {
207
                        return
208
                }
209
                src := cast.ToString(value.Interface())
210
                if utils.IsStrBlank(src) {
211
                        return
212
                }
213
214
                dst := utils.Must(encode.From(src).Decode(opts...).ToString())
215
                value.SetString(dst)
216
                return
217
        })
218
}
func registry.makeComponentsConfigFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

305
func (p *registry) makeComponentsConfigFields() []reflect.StructField {
306
        fieldList := make([]reflect.StructField, len(p.componentList))
307
        for i := 0; i < len(p.componentList); i++ {
308
                component := p.componentList[i]
309
                fieldList[i] = reflect.StructField{
310
                        Name: component.Name,
311
                        Type: component.ConstructorInputType,
312
                        Tag:  reflect.StructTag(component.Tag),
313
                }
314
        }
315
316
        return fieldList
317
}
func @355:26
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

355
func() {
356
                // app
357
                p.AddComponent(ComponentApp, func(context.Context, string, ...utils.OptionExtender) func() { return nil },
358
                        WithTag("yaml", "app"), WithTag("json", "app"), WithTag("toml", "app"))
359
360
                // debug
361
                p.AddComponent(ComponentDebug, func(context.Context, bool, ...utils.OptionExtender) func() { return nil },
362
                        WithTag("yaml", "debug"), WithTag("json", "debug"), WithTag("toml", "debug"))
363
364
                // crypto
365
                p.AddComponent(ComponentCrypto, CryptoConstruct,
366
                        WithTag("yaml", "crypto"), WithTag("json", "crypto"), WithTag("toml", "crypto"))
367
368
                for _, item := range getComponents() {
369
                        p.AddComponent(item.name, item.constructor, item.opt...)
370
                }
371
372
                /* example */
373
                // registry.AddComponent("ComponentExample", func(context.Context, string) func() { return nil },
374
                //    WithTag("custom_tag", "val"), WithTag("yaml", "val"))
375
        }
func registry.AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/candy.go:

21
func (p *registry) AppName() (name string) {
22
        if p.appName != "" {
23
                return p.appName
24
        }
25
        _ = p.LoadComponentConfig(ComponentApp, &name)
26
        return
27
}
func AddComponent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

123
func AddComponent(name string, constructor any, opts ...ComponentOption) {
124
        componentLocker.Lock()
125
        defer componentLocker.Unlock()
126
        parseConstructor(constructor)
127
        components = append(components, &componentItem{name, constructor, opts})
128
}
func registry.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/candy.go:

13
func (p *registry) Debug() (debug bool) {
14
        if p.appName != "" {
15
                return p.debug
16
        }
17
        _ = p.LoadComponentConfig(ComponentDebug, &debug)
18
        return
19
}
func getComponents
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

130
func getComponents() []*componentItem {
131
        componentLocker.RLock()
132
        defer componentLocker.RUnlock()
133
        return clone.Clone(components)
134
}
func registry.makeComponentsConfigStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

293
func (p *registry) makeComponentsConfigStruct() reflect.Type {
294
        fieldList := p.makeComponentsConfigFields()
295
        return reflect.StructOf([]reflect.StructField{
296
                {
297
                        Name:      componentConfigFieldName,
298
                        Type:      reflect.StructOf(fieldList),
299
                        Tag:       `yaml:"base" json:"base" toml:"base"`,
300
                        Anonymous: true,
301
                },
302
        })
303
}
func @96:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

96
func(o *initOption) {
97
                o.filenames = filenames
98
        }
func DI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/types.go:

28
func DI(di di.DI) utils.OptionFunc[InitOption] {
29
        return func(o *InitOption) {
30
                o.DI = di
31
        }
32
}
func @23:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/types.go:

23
func(o *InitOption) {
24
                o.AppName = name
25
        }
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/types.go:

22
func AppName(name string) utils.OptionFunc[InitOption] {
23
        return func(o *InitOption) {
24
                o.AppName = name
25
        }
26
}
func WithTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

104
func WithTag(name, val string) ComponentOption {
105
        return func(opt *options) {
106
                opt.TagList = append(opt.TagList, fmt.Sprintf(`%s:"%s"`, name, val))
107
        }
108
}
func @29:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/types.go:

29
func(o *InitOption) {
30
                o.DI = di
31
        }
func registry.DI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/candy.go:

29
func (p *registry) DI() di.DI { return p.di }
func @418:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

418
func() {
419
                once.Do(func() {
420
                        initLocker.Lock()
421
                        defer initLocker.Unlock()
422
423
                        defer close(p.closeCh)
424
425
                        p.initWg.Done()
426
                        p.initWg.Wait()
427
                        cancel()
428
                        for i := len(destructors) - 1; i >= 0; i-- {
429
                                log.Printf("%v [Gofusion] %s %s exiting...", pid, app, hasCallbackComponentNames[i])
430
                                destructors[i].Call(nil)
431
                                log.Printf("%v [Gofusion] %s %s exited", pid, app, hasCallbackComponentNames[i])
432
                        }
433
434
                        p.di.Clear()
435
                        p.businessConfig = nil
436
                        p.componentConfigs = nil
437
                        p.initOnce = new(sync.Once)
438
                })
439
        }
func registry.getBaseObject
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

289
func (p *registry) getBaseObject() reflect.Value {
290
        return reflect.Indirect(reflect.ValueOf(p.componentConfigs)).FieldByName(componentConfigFieldName)
291
}
func @361:34
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

361
func(context.Context, bool, ...utils.OptionExtender) func() { return nil }
func registry.loadComponents
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

354
func (p *registry) loadComponents() {
355
        p.loadComponentsOnce.Do(func() {
356
                // app
357
                p.AddComponent(ComponentApp, func(context.Context, string, ...utils.OptionExtender) func() { return nil },
358
                        WithTag("yaml", "app"), WithTag("json", "app"), WithTag("toml", "app"))
359
360
                // debug
361
                p.AddComponent(ComponentDebug, func(context.Context, bool, ...utils.OptionExtender) func() { return nil },
362
                        WithTag("yaml", "debug"), WithTag("json", "debug"), WithTag("toml", "debug"))
363
364
                // crypto
365
                p.AddComponent(ComponentCrypto, CryptoConstruct,
366
                        WithTag("yaml", "crypto"), WithTag("json", "crypto"), WithTag("toml", "crypto"))
367
368
                for _, item := range getComponents() {
369
                        p.AddComponent(item.name, item.constructor, item.opt...)
370
                }
371
372
                /* example */
373
                // registry.AddComponent("ComponentExample", func(context.Context, string) func() { return nil },
374
                //    WithTag("custom_tag", "val"), WithTag("yaml", "val"))
375
        })
376
}
func NewDefaultLoader
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/loader.go:

23
func NewDefaultLoader(files ...string) *loader {
24
        return &loader{
25
                files: files,
26
        }
27
}
func loader.Unmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/loader.go:

31
func (l *loader) Unmarshal(out any) (err error) {
32
        return configor.New(&configor.Config{
33
                Environment:        env.GetEnv(),
34
                ENVPrefix:          "",
35
                Debug:              false,
36
                Verbose:            false,
37
                Silent:             true,
38
                AutoReload:         true,
39
                AutoReloadInterval: 0,
40
                AutoReloadCallback: func(config any) {
41
                        log.Printf("%v [Gofusion] Config auto reload config successfully => \n%s",
42
                                syscall.Getpid(), utils.Must(yaml.Marshal(config)))
43
                },
44
                ErrorOnUnmatchedKeys: false,
45
                FS:                   nil,
46
        }).Load(out, l.files...)
47
}
func @40:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/loader.go:

40
func(config any) {
41
                        log.Printf("%v [Gofusion] Config auto reload config successfully => \n%s",
42
                                syscall.Getpid(), utils.Must(yaml.Marshal(config)))
43
                }
func @136:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

136
func() {
137
                        once.Do(func() {
138
                                p.initWg.Done()
139
                        })
140
                }
func newOptions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

99
func newOptions() *options {
100
        return &options{}
101
}
func @357:32
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

357
func(context.Context, string, ...utils.OptionExtender) func() { return nil }
func @105:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

105
func(opt *options) {
106
                opt.TagList = append(opt.TagList, fmt.Sprintf(`%s:"%s"`, name, val))
107
        }
func Ctx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

83
func Ctx(ctx context.Context) utils.OptionFunc[initOption] {
84
        return func(o *initOption) {
85
                o.bizCtx = ctx
86
        }
87
}
func @84:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

84
func(o *initOption) {
85
                o.bizCtx = ctx
86
        }
func Loader
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

89
func Loader(fn func(any, ...utils.OptionExtender)) utils.OptionFunc[initOption] {
90
        return func(o *initOption) {
91
                o.customLoadFunc = fn
92
        }
93
}
func @90:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

90
func(o *initOption) {
91
                o.customLoadFunc = fn
92
        }
func Files
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

95
func Files(filenames []string) utils.OptionFunc[initOption] {
96
        return func(o *initOption) {
97
                o.filenames = filenames
98
        }
99
}
func @137:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

137
func() {
138
                                p.initWg.Done()
139
                        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/loader.go:

55
func init() {
56
        flag.StringVar(&customConfigPath, "configPath", "", "config file path")
57
}
func @192:35
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

192
func(field reflect.StructField, value reflect.Value) (end, stepIn bool) {
193
                if !value.IsValid() || !value.CanInterface() || !value.CanSet() {
194
                        return
195
                }
196
197
                vk := value.Kind()
198
                stepIn = supportedFields.Contains(vk) ||
199
                        (vk == reflect.Ptr && value.Elem().IsValid() && value.Elem().Kind() == reflect.Struct)
200
201
                configName, ok := field.Tag.Lookup(cryptoTagKey)
202
                if !ok {
203
                        return
204
                }
205
                opts, ok := optsMap[configName]
206
                if !ok {
207
                        return
208
                }
209
                src := cast.ToString(value.Interface())
210
                if utils.IsStrBlank(src) {
211
                        return
212
                }
213
214
                dst := utils.Must(encode.From(src).Decode(opts...).ToString())
215
                value.SetString(dst)
216
                return
217
        }
func registry.AddComponent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

145
func (p *registry) AddComponent(name string, constructor any, opts ...ComponentOption) {
146
        if name[0] < 'A' || name[0] > 'Z' {
147
                panic("component name should start with A-Z")
148
        }
149
        for idx, com := range p.componentList {
150
                if com.Name == name {
151
                        p.componentList = append(p.componentList[:idx], p.componentList[idx+1:]...)
152
                }
153
        }
154
        opt := newOptions()
155
        for _, fn := range opts {
156
                fn(opt)
157
        }
158
159
        com := &Component{
160
                Name:   name,
161
                isCore: opt.IsCoreComponent,
162
        }
163
164
        hasYamlTag := false
165
        hasJsonTag := false
166
        hasTomlTag := false
167
        for _, tag := range opt.TagList {
168
                hasYamlTag = strings.HasPrefix(tag, "`yaml:")
169
                hasJsonTag = strings.HasPrefix(tag, "`json:")
170
                hasTomlTag = strings.HasPrefix(tag, "`toml:")
171
        }
172
        lowerName := strcase.ToSnake(name)
173
        if name == ComponentI18n {
174
                lowerName = strings.ToLower(name)
175
        }
176
        if !hasYamlTag {
177
                opt.TagList = append(opt.TagList, fmt.Sprintf(`yaml:"%s"`, lowerName))
178
        }
179
        if !hasJsonTag {
180
                opt.TagList = append(opt.TagList, fmt.Sprintf(`json:"%s"`, lowerName))
181
        }
182
        if !hasTomlTag {
183
                opt.TagList = append(opt.TagList, fmt.Sprintf(`toml:"%s"`, lowerName))
184
        }
185
        if len(opt.TagList) > 0 {
186
                com.Tag = strings.Join(opt.TagList, " ")
187
        }
188
189
        com.Constructor, com.ConstructorInputType = parseConstructor(constructor)
190
191
        p.addComponent(com)
192
}
func @36:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/candy.go:

36
func(c *cryptoConf) {
37
                if c == nil {
38
                        return
39
                }
40
                c.Algorithm = cipher.ParseAlgorithm(c.AlgorithmString)
41
                c.Mode = cipher.ParseMode(c.ModeString)
42
                c.Key = utils.Must(base64.StdEncoding.DecodeString(c.KeyBase64))
43
                c.IV = utils.Must(base64.StdEncoding.DecodeString(c.IVBase64))
44
45
                if utils.IsStrPtrNotBlank(c.CompressAlgorithmString) {
46
                        c.CompressAlgorithm = compress.ParseAlgorithm(*c.CompressAlgorithmString)
47
                }
48
                if utils.IsStrPtrNotBlank(c.OutputAlgorithmString) {
49
                        c.OutputAlgorithm = encode.ParseAlgorithm(*c.OutputAlgorithmString)
50
                }
51
        }
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

34
func Use(appName string, opts ...utils.OptionExtender) Configurable {
35
        registryLock.RLock()
36
        defer registryLock.RUnlock()
37
        cfg, ok := registryMap[appName]
38
        if !ok {
39
                panic(errors.Errorf("app register config not found: %s", appName))
40
        }
41
        return cfg
42
}
func CryptoConf.ToOptionMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

28
func (c *CryptoConf) ToOptionMap() (result map[string][]utils.OptionExtender) {
29
        result = make(map[string][]utils.OptionExtender)
30
        if c.Config != nil {
31
                result[""] = c.Config.ToOptions()
32
        }
33
        for name, cfg := range c.Custom {
34
                result[name] = cfg.ToOptions()
35
        }
36
        return
37
}
func cryptoConf.ToOptions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

62
func (c *cryptoConf) ToOptions() (opts []utils.OptionExtender) {
63
        if !c.Algorithm.IsValid() {
64
                return nil
65
        }
66
67
        if c.ConfuseKey {
68
                c.Key = c.cryptoConfuseKey(c.Key)
69
        }
70
71
        opts = make([]utils.OptionExtender, 0, 3)
72
        opts = append(opts, encode.Cipher(c.Algorithm, c.Mode, c.Key, c.IV))
73
        if c.CompressAlgorithm.IsValid() {
74
                opts = append(opts, encode.Compress(c.CompressAlgorithm))
75
        }
76
        if c.OutputAlgorithm.IsValid() {
77
                opts = append(opts, encode.Encode(c.OutputAlgorithm))
78
        }
79
        return
80
}
func registry.cryptoConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/candy.go:

31
func (p *registry) cryptoConfig() (conf *CryptoConf) {
32
        conf = new(CryptoConf)
33
        if err := p.LoadComponentConfig(ComponentCrypto, &conf); err != nil {
34
                return
35
        }
36
        parseCfgFunc := func(c *cryptoConf) {
37
                if c == nil {
38
                        return
39
                }
40
                c.Algorithm = cipher.ParseAlgorithm(c.AlgorithmString)
41
                c.Mode = cipher.ParseMode(c.ModeString)
42
                c.Key = utils.Must(base64.StdEncoding.DecodeString(c.KeyBase64))
43
                c.IV = utils.Must(base64.StdEncoding.DecodeString(c.IVBase64))
44
45
                if utils.IsStrPtrNotBlank(c.CompressAlgorithmString) {
46
                        c.CompressAlgorithm = compress.ParseAlgorithm(*c.CompressAlgorithmString)
47
                }
48
                if utils.IsStrPtrNotBlank(c.OutputAlgorithmString) {
49
                        c.OutputAlgorithm = encode.ParseAlgorithm(*c.OutputAlgorithmString)
50
                }
51
        }
52
53
        if conf != nil {
54
                parseCfgFunc(conf.Config)
55
                conf.Custom = make(map[string]*cryptoConf)
56
                for _, c := range conf.Custom {
57
                        parseCfgFunc(c)
58
                }
59
        }
60
61
        return
62
}
func loadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/loader.go:

59
func loadConfig(out any, opts ...utils.OptionExtender) {
60
        if !flag.Parsed() {
61
                flag.Parse()
62
        }
63
64
        opt := utils.ApplyOptions[initOption](opts...)
65
66
        files := make([]string, 0, 2)
67
        switch {
68
        case utils.IsStrNotBlank(customConfigPath):
69
                files = append(files, filepath.Clean(customConfigPath))
70
        case len(opt.filenames) > 0:
71
                files = append(files, opt.filenames...)
72
        default:
73
                defaultPathPrefix := filepath.Join(env.WorkDir, "configs", "app.")
74
                defaultLocal1PathPrefix := filepath.Join(env.WorkDir, "configs", "app.local.")
75
                defaultLocal2PathPrefix := filepath.Join(env.WorkDir, "configs", "app_local.")
76
                defaultLocal3PathPrefix := filepath.Join(env.WorkDir, "configs", "app-local.")
77
                extensions := []string{"yaml", "yml", "json", "toml"}
78
                for _, ext := range extensions {
79
                        localFilename := defaultLocal1PathPrefix + ext
80
                        if _, err := os.Stat(localFilename); err == nil {
81
                                files = append(files, localFilename)
82
                                continue
83
                        }
84
                        localFilename = defaultLocal2PathPrefix + ext
85
                        if _, err := os.Stat(localFilename); err == nil {
86
                                files = append(files, localFilename)
87
                                continue
88
                        }
89
                        localFilename = defaultLocal3PathPrefix + ext
90
                        if _, err := os.Stat(localFilename); err == nil {
91
                                files = append(files, localFilename)
92
                                continue
93
                        }
94
                }
95
                for _, ext := range extensions {
96
                        defaultFilename := defaultPathPrefix + ext
97
                        if _, err := os.Stat(defaultFilename); err == nil {
98
                                files = append(files, defaultFilename)
99
                        }
100
                }
101
        }
102
103
        // check if configure file exists first, to avoid auto reload a nonexistent file
104
        existFiles := make([]string, 0, len(files))
105
        for _, name := range files {
106
                if _, err := os.Stat(name); err == nil {
107
                        existFiles = append(existFiles, name)
108
                }
109
        }
110
111
        if profile != "" {
112
                if err := configor.New(&configor.Config{Environment: profile}).Load(out, existFiles...); err != nil {
113
                        panic(errors.Errorf("parse config file of config env %s error: %v", profile, err))
114
                }
115
                return
116
        }
117
118
        if err := NewDefaultLoader(files...).Unmarshal(out); err != nil {
119
                panic(errors.Errorf("parse config file error! %s", err))
120
        }
121
}
func registry.LoadComponentConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

194
func (p *registry) LoadComponentConfig(name string, componentConfig any) (err error) {
195
        val := reflect.ValueOf(componentConfig)
196
        typ := val.Type()
197
        if typ.Kind() != reflect.Ptr {
198
                return errors.New("componentConfig should be pointer")
199
        }
200
201
        var found bool
202
        for _, com := range p.componentList {
203
                if com.Name == name {
204
                        found = true
205
                        break
206
                }
207
        }
208
        if !found {
209
                return errors.Errorf("no such component [%s]", name)
210
        }
211
212
        // load config
213
        if p.componentConfigs == nil {
214
                return
215
        }
216
        componentConfigsValue := utils.IndirectValue(reflect.ValueOf(clone.Clone(p.componentConfigs)))
217
        if !componentConfigsValue.IsValid() {
218
                return errors.Errorf("component configs not initialize now [%s]", name)
219
        }
220
        componentConfigValue := componentConfigsValue.FieldByName(componentConfigFieldName).FieldByName(name)
221
222
        if componentConfigValue.Type().Kind() == reflect.Ptr {
223
                if componentConfigValue.IsNil() {
224
                        return
225
                }
226
                componentConfigValue = componentConfigValue.Elem()
227
        }
228
        if componentConfigValue.Type() == typ.Elem() || componentConfigValue.Type().ConvertibleTo(typ.Elem()) {
229
                val.Elem().Set(reflect.ValueOf(clone.Clone(componentConfigValue.Convert(typ.Elem()).Interface())))
230
                return
231
        }
232
233
        decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
234
                Metadata:         nil,
235
                Result:           componentConfig,
236
                TagName:          "yaml",
237
                WeaklyTypedInput: true,
238
        })
239
        if err != nil {
240
                return
241
        }
242
        return decoder.Decode(componentConfigValue.Interface())
243
}
func @452:37
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

452
func(i, j int) bool {
453
                        // core component would not be sorted
454
                        if p.componentList[i].isCore || p.componentList[j].isCore {
455
                                return false
456
                        }
457
458
                        orderA := indexComponent(p.componentList[i].Name)
459
                        if orderA == -1 {
460
                                return false
461
                        }
462
                        orderB := indexComponent(p.componentList[j].Name)
463
                        if orderB == -1 {
464
                                return true
465
                        }
466
467
                        return orderA < orderB
468
                }
func registry.checkBusinessConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

486
func (p *registry) checkBusinessConfig(businessConfig any) {
487
        typ := reflect.TypeOf(businessConfig)
488
        if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Ptr {
489
                panic(errors.New("businessConfig should be a **struct"))
490
        }
491
}
func parseConstructor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

136
func parseConstructor(fn any) (fnVal reflect.Value, input reflect.Type) {
137
        fnVal = reflect.ValueOf(fn)
138
        typ := reflect.TypeOf(fn)
139
        if typ.Kind() != reflect.Func {
140
                panic(errors.New("component constructor should be a function"))
141
        }
142
143
        // check output
144
        if typ.NumOut() != 1 {
145
                panic(errors.New("component constructor should return one finalizer function"))
146
        }
147
        retTyp := typ.Out(0)
148
        if retTyp.Kind() != reflect.Func {
149
                panic(errors.New("component constructor should return one finalizer function"))
150
        }
151
        if retTyp.NumIn() != 0 {
152
                panic(errors.New("component constructor should return one finalizer function looks like func()"))
153
        }
154
155
        // check input
156
        fnType := fnVal.Type()
157
        if n := fnType.NumIn(); n != 1 && (!fnType.IsVariadic() && n != 3) {
158
                panic(errors.New("component constructor should receive input looks like " +
159
                        "func(context.Context), func(context.Context, *serializableConf, ...utils.OptionExtender)"))
160
        }
161
        if fnType.In(0) != constant.ContextType {
162
                panic(errors.New("component constructor should receive context.Context as first input " +
163
                        "looks like func(context.Context), func(context.Context, *serializableConf, ...utils.OptionExtender)"))
164
        }
165
166
        // wrapper
167
        switch typ.NumIn() {
168
        case 1:
169
                input = reflect.TypeOf(int(0))
170
                fnVal = reflect.ValueOf(func(ctx context.Context, mock int, _ ...utils.OptionExtender) func() {
171
                        out := reflect.ValueOf(fn).Call([]reflect.Value{reflect.ValueOf(ctx)})
172
                        if retfn := out[0]; retfn.IsNil() {
173
                                return nil
174
                        } else if obj := retfn.Interface(); obj == nil {
175
                                return nil
176
                        } else if fn, ok := obj.(func()); !ok {
177
                                return nil
178
                        } else {
179
                                return fn
180
                        }
181
                })
182
        case 3:
183
                input = typ.In(1)
184
                argsType := typ.In(2)
185
                if argsType.Kind() != reflect.Slice ||
186
                        argsType.Elem() != reflect.TypeOf((*utils.OptionExtender)(nil)).Elem() {
187
                        panic(errors.New("component constructor only receive utils.OptionExtender variadic input"))
188
                }
189
        default:
190
                panic(errors.New("component constructor should receive one or three inputs looks like " +
191
                        "func(context.Context), func(context.Context, *serializableConf, ...utils.OptionExtender)"))
192
        }
193
        return
194
}
func indexComponent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

64
func indexComponent(name string) (idx int) {
65
        for idx = 0; idx < len(componentOrder); idx++ {
66
                if componentOrder[idx] == name {
67
                        return
68
                }
69
        }
70
        idx = -1
71
        return
72
}
func checkCryptoConf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

116
func checkCryptoConf(name string, c *cryptoConf) {
117
        // cipher
118
        if c.Algorithm = cipher.ParseAlgorithm(c.AlgorithmString); !c.Algorithm.IsValid() {
119
                panic(errors.Errorf("unknown config %s algorithm: %s", name, c.AlgorithmString))
120
        }
121
        c.Mode = cipher.ParseMode(c.ModeString)
122
        if !c.Mode.IsValid() {
123
                panic(errors.Errorf("unknown config %s mode: %s", name, c.ModeString))
124
        }
125
        if utils.IsStrBlank(c.KeyBase64) {
126
                panic(errors.Errorf("%s not found crypto key", name))
127
        }
128
        c.Key = utils.Must(base64.StdEncoding.DecodeString(c.KeyBase64))
129
        if c.Mode.NeedIV() && utils.IsStrBlank(c.IVBase64) {
130
                panic(errors.Errorf("%s not found crypto iv", name))
131
        }
132
        c.IV = utils.Must(base64.StdEncoding.DecodeString(c.IVBase64))
133
134
        // compress
135
        if utils.IsStrPtrNotBlank(c.CompressAlgorithmString) {
136
                c.CompressAlgorithm = compress.ParseAlgorithm(*c.CompressAlgorithmString)
137
                if !c.CompressAlgorithm.IsValid() {
138
                        panic(errors.Errorf("unknown config %s compress algorithm: %s", name, *c.CompressAlgorithmString))
139
                }
140
        }
141
142
        // output
143
        if utils.IsStrPtrNotBlank(c.OutputAlgorithmString) {
144
                c.OutputAlgorithm = encode.ParseAlgorithm(*c.OutputAlgorithmString)
145
                if !c.OutputAlgorithm.IsValid() {
146
                        panic(errors.Errorf("unknown config %s output algorithm: %s", name, *c.OutputAlgorithmString))
147
                }
148
        }
149
}
func registry.addComponent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

442
func (p *registry) addComponent(com *Component) {
443
        firstNonCoreComIndex := -1
444
        for i, cp := range p.componentList {
445
                if !cp.isCore {
446
                        firstNonCoreComIndex = i
447
                        break
448
                }
449
        }
450
        if !com.isCore || firstNonCoreComIndex == -1 {
451
                p.componentList = append(p.componentList, com)
452
                sort.SliceStable(p.componentList, func(i, j int) bool {
453
                        // core component would not be sorted
454
                        if p.componentList[i].isCore || p.componentList[j].isCore {
455
                                return false
456
                        }
457
458
                        orderA := indexComponent(p.componentList[i].Name)
459
                        if orderA == -1 {
460
                                return false
461
                        }
462
                        orderB := indexComponent(p.componentList[j].Name)
463
                        if orderB == -1 {
464
                                return true
465
                        }
466
467
                        return orderA < orderB
468
                })
469
470
                return
471
        }
472
        list := make([]*Component, len(p.componentList)+1)
473
        for i := range list {
474
                if i < firstNonCoreComIndex {
475
                        list[i] = p.componentList[i]
476
                } else if i == firstNonCoreComIndex {
477
                        list[i] = com
478
                } else {
479
                        list[i] = p.componentList[i-1]
480
                }
481
        }
482
483
        p.componentList = list
484
}
func @170:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

170
func(ctx context.Context, mock int, _ ...utils.OptionExtender) func() {
171
                        out := reflect.ValueOf(fn).Call([]reflect.Value{reflect.ValueOf(ctx)})
172
                        if retfn := out[0]; retfn.IsNil() {
173
                                return nil
174
                        } else if obj := retfn.Interface(); obj == nil {
175
                                return nil
176
                        } else if fn, ok := obj.(func()); !ok {
177
                                return nil
178
                        } else {
179
                                return fn
180
                        }
181
                }
func CryptoDecryptFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

171
func CryptoDecryptFunc(opts ...utils.OptionExtender) func(src string) (dst string) {
172
        o := utils.ApplyOptions[InitOption](opts...)
173
        opt := utils.ApplyOptions[cryptoConfigOption](opts...)
174
        optsMap := Use(o.AppName).(*registry).cryptoConfig().ToOptionMap()
175
        for _, opts := range optsMap {
176
                utils.SliceReverse(opts)
177
        }
178
        opts = optsMap[opt.name]
179
        return func(src string) (dst string) {
180
                return utils.Must(encode.From(src).Decode(opts...).ToString())
181
        }
182
}
func CryptoEncryptFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

161
func CryptoEncryptFunc(opts ...utils.OptionExtender) func(src string) (dst string) {
162
        o := utils.ApplyOptions[InitOption](opts...)
163
        opt := utils.ApplyOptions[cryptoConfigOption](opts...)
164
        optsMap := Use(o.AppName).(*registry).cryptoConfig().ToOptionMap()
165
        opts = optsMap[opt.name]
166
        return func(src string) (dst string) {
167
                return utils.Must(encode.From(src).Encode(opts...).ToString())
168
        }
169
}
func @156:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

156
func(o *cryptoConfigOption) {
157
                o.name = name
158
        }
func Component.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

82
func (c *Component) Clone() (r *Component) {
83
        return &Component{
84
                Name:                 c.Name,
85
                Tag:                  c.Tag,
86
                Constructor:          c.Constructor,
87
                ConstructorInputType: c.ConstructorInputType,
88
                isCore:               c.isCore,
89
        }
90
}
func Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

101
func Debug() utils.OptionFunc[initOption] {
102
        return func(o *initOption) {
103
                o.debug = true
104
        }
105
}
func @166:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

166
func(src string) (dst string) {
167
                return utils.Must(encode.From(src).Encode(opts...).ToString())
168
        }
func @179:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

179
func(src string) (dst string) {
180
                return utils.Must(encode.From(src).Decode(opts...).ToString())
181
        }
func @112:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

112
func(opt *options) {
113
                opt.IsCoreComponent = true
114
        }
func CryptoConfigName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

155
func CryptoConfigName(name string) utils.OptionFunc[cryptoConfigOption] {
156
        return func(o *cryptoConfigOption) {
157
                o.name = name
158
        }
159
}
func WithCore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/component.go:

111
func WithCore() ComponentOption {
112
        return func(opt *options) {
113
                opt.IsCoreComponent = true
114
        }
115
}
func @102:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/registry.go:

102
func(o *initOption) {
103
                o.debug = true
104
        }
func @111:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/config/crypto.go:

111
func() {
112
113
        }
Package Overview: github.com/wfusion/gofusion/context 75.0%

Please select a function to see what's left for testing.

_context.Marshal(...) github.com/wfusion/gofusion/context/context.go 100.0% 6/6
@182:9(...) github.com/wfusion/gofusion/context/context.go 100.0% 2/2
@146:14(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
SetTraceID(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
GetLangs(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
Watermill(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
GetCronTaskID(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
@189:9(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
GetCronTaskName(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
SetCronTaskName(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
Gin(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
GetTraceID(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
GetUserID(...) github.com/wfusion/gofusion/context/candy.go 100.0% 1/1
@195:9(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
Context(...) github.com/wfusion/gofusion/context/context.go 100.0% 1/1
newOption.messageUnmarshal(...) github.com/wfusion/gofusion/context/context.go 75.0% 18/24
Flatten(...) github.com/wfusion/gofusion/context/context.go 73.3% 11/15
New(...) github.com/wfusion/gofusion/context/context.go 71.4% 5/7
_context.unmarshal(...) github.com/wfusion/gofusion/context/context.go 70.6% 12/17
newOption.ginUnmarshal(...) github.com/wfusion/gofusion/context/context.go 69.2% 9/13
WatermillMetadata(...) github.com/wfusion/gofusion/context/context.go 68.8% 11/16
SetCronTaskID(...) github.com/wfusion/gofusion/context/candy.go 0.0% 0/1
SetLangs(...) github.com/wfusion/gofusion/context/candy.go 0.0% 0/1
SetUserID(...) github.com/wfusion/gofusion/context/candy.go 0.0% 0/1
func _context.Marshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

58
func (c *_context) Marshal() (b []byte) {
59
        bs, cb := utils.BytesBufferPool.Get(nil)
60
        defer cb()
61
        utils.MustSuccess(gob.NewEncoder(bs).Encode(c))
62
63
        b = make([]byte, bs.Len())
64
        copy(b, bs.Bytes())
65
        return
66
}
func @182:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

182
func(o *newOption) {
183
                o.c = new(_context)
184
                utils.MustSuccess(utils.Unmarshal(c, o.c, ""))
185
        }
func @146:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

146
func(k string) string { return o.m[k] }
func SetTraceID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

21
func SetTraceID(ctx context.Context, val string) context.Context {
22
        return utils.SetCtxAny(ctx, KeyTraceID, val)
23
}
func GetLangs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

25
func GetLangs(ctx context.Context, args ...[]string) (langs []string) {
26
        return utils.GetCtxAny(ctx, KeyLangs, args...)
27
}
func Watermill
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

194
func Watermill(m message.Metadata) utils.OptionFunc[newOption] {
195
        return func(o *newOption) {
196
                o.m = m
197
        }
198
}
func GetCronTaskID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

33
func GetCronTaskID(ctx context.Context, args ...string) (userID string) {
34
        return utils.GetCtxAny(ctx, KeyCronTaskID, args...)
35
}
func @189:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

189
func(o *newOption) {
190
                o.g = c
191
        }
func GetCronTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

41
func GetCronTaskName(ctx context.Context, args ...string) (userID string) {
42
        return utils.GetCtxAny(ctx, KeyCronTaskName, args...)
43
}
func SetCronTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

45
func SetCronTaskName(ctx context.Context, val string) context.Context {
46
        return utils.SetCtxAny(ctx, KeyCronTaskName, val)
47
}
func Gin
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

188
func Gin(c *gin.Context) utils.OptionFunc[newOption] {
189
        return func(o *newOption) {
190
                o.g = c
191
        }
192
}
func GetTraceID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

17
func GetTraceID(ctx context.Context, args ...string) (traceID string) {
18
        return utils.GetCtxAny(ctx, KeyTraceID, args...)
19
}
func GetUserID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

9
func GetUserID(ctx context.Context, args ...string) (userID string) {
10
        return utils.GetCtxAny(ctx, KeyUserID, args...)
11
}
func @195:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

195
func(o *newOption) {
196
                o.m = m
197
        }
func Context
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

181
func Context(c []byte) utils.OptionFunc[newOption] {
182
        return func(o *newOption) {
183
                o.c = new(_context)
184
                utils.MustSuccess(utils.Unmarshal(c, o.c, ""))
185
        }
186
}
func newOption.messageUnmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

144
func (o *newOption) messageUnmarshal() (ctx context.Context) {
145
        ctx = context.Background()
146
        mapGetFn := func(k string) string { return o.m[k] }
147
        if userID := utils.LookupByFuzzyKeyword[string](mapGetFn, "user_id"); utils.IsStrNotBlank(userID) {
148
                ctx = SetUserID(ctx, userID)
149
        }
150
        if traceID := utils.LookupByFuzzyKeyword[string](mapGetFn, "trace_id"); utils.IsStrNotBlank(traceID) {
151
                ctx = SetTraceID(ctx, traceID)
152
        }
153
        if langstr := utils.LookupByFuzzyKeyword[string](mapGetFn, "langs"); utils.IsStrNotBlank(langstr) {
154
                var langs []string
155
                _ = json.Unmarshal([]byte(langstr), &langs)
156
                ctx = SetLangs(ctx, langs)
157
        }
158
        if taskID := utils.LookupByFuzzyKeyword[string](mapGetFn, "cron_task_id"); utils.IsStrNotBlank(taskID) {
159
                ctx = SetCronTaskID(ctx, taskID)
160
        }
161
        if name := utils.LookupByFuzzyKeyword[string](mapGetFn, "cron_task_name"); utils.IsStrNotBlank(name) {
162
                ctx = SetCronTaskName(ctx, name)
163
        }
164
        if messageUUID := o.m[watermill.ContextKeyMessageUUID]; utils.IsStrNotBlank(messageUUID) {
165
                ctx = utils.SetCtxAny(ctx, watermill.ContextKeyMessageUUID, messageUUID)
166
        }
167
        if messageRawID := o.m[watermill.ContextKeyRawMessageID]; utils.IsStrNotBlank(messageRawID) {
168
                ctx = utils.SetCtxAny(ctx, watermill.ContextKeyRawMessageID, messageRawID)
169
        }
170
171
        deadline := utils.LookupByFuzzyKeyword[string](mapGetFn, "deadline")
172
        deadlineLoc := utils.LookupByFuzzyKeyword[string](mapGetFn, "deadline_location")
173
        if utils.IsStrNotBlank(deadline) {
174
                location := utils.Must(time.LoadLocation(deadlineLoc))
175
                // FIXME: it may result context leak issue
176
                ctx, _ = context.WithDeadline(ctx, utils.Must(time.ParseInLocation(time.RFC3339Nano, deadline, location)))
177
        }
178
        return
179
}
func Flatten
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

68
func Flatten(ctx context.Context) (c *_context) {
69
        c = new(_context)
70
        if langs := GetLangs(ctx); langs != nil {
71
                c.Langs = langs
72
        }
73
        if userID := GetUserID(ctx); utils.IsStrNotBlank(userID) {
74
                c.UserID = utils.AnyPtr(userID)
75
        }
76
        if traceID := GetTraceID(ctx); utils.IsStrNotBlank(traceID) {
77
                c.TraceID = utils.AnyPtr(traceID)
78
        }
79
        if taskID := GetCronTaskID(ctx); utils.IsStrNotBlank(taskID) {
80
                c.CronTaskID = utils.AnyPtr(taskID)
81
        }
82
        if taskName := GetCronTaskName(ctx); utils.IsStrNotBlank(taskName) {
83
                c.CronTaskName = utils.AnyPtr(taskName)
84
        }
85
        if deadline, ok := ctx.Deadline(); ok {
86
                c.Deadline = utils.AnyPtr(deadline.Format(time.RFC3339Nano))
87
                c.DeadlineLocation = utils.AnyPtr(deadline.Location().String())
88
        }
89
        return
90
}
func New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

200
func New(opts ...utils.OptionExtender) (ctx context.Context) {
201
        o := utils.ApplyOptions[newOption](opts...)
202
203
        // alternative
204
        switch {
205
        case o.g != nil:
206
                return o.ginUnmarshal()
207
        case o.c != nil:
208
                return o.c.unmarshal()
209
        case o.m != nil:
210
                return o.messageUnmarshal()
211
        default:
212
                panic(ErrUnknownInstantiationMethod)
213
        }
214
215
        return
216
}
func _context.unmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

28
func (c *_context) unmarshal() (ctx context.Context) {
29
        ctx = context.Background()
30
        if c == nil {
31
                return
32
        }
33
34
        if c.Langs != nil {
35
                ctx = SetLangs(ctx, c.Langs)
36
        }
37
        if c.UserID != nil {
38
                ctx = SetUserID(ctx, *c.UserID)
39
        }
40
        if c.TraceID != nil {
41
                ctx = SetTraceID(ctx, *c.TraceID)
42
        }
43
        if c.CronTaskID != nil {
44
                ctx = SetCronTaskID(ctx, *c.CronTaskID)
45
        }
46
        if c.CronTaskName != nil {
47
                ctx = SetCronTaskName(ctx, *c.CronTaskName)
48
        }
49
        if c.Deadline != nil {
50
                location := utils.Must(time.LoadLocation(*c.DeadlineLocation))
51
                // FIXME: it may result context leak issue
52
                ctx, _ = context.WithDeadline(ctx, utils.Must(time.ParseInLocation(time.RFC3339Nano, *c.Deadline, location)))
53
        }
54
55
        return
56
}
func newOption.ginUnmarshal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

123
func (o *newOption) ginUnmarshal() (ctx context.Context) {
124
        ctx = context.Background()
125
        if userID := o.g.GetString(KeyUserID); utils.IsStrNotBlank(userID) {
126
                ctx = SetUserID(ctx, userID)
127
        }
128
        if traceID := o.g.GetString(KeyTraceID); utils.IsStrNotBlank(traceID) {
129
                ctx = SetTraceID(ctx, traceID)
130
        }
131
        langs := o.g.Request.Header.Values("Accept-Language")
132
        if lang := o.g.GetString("lang"); utils.IsStrNotBlank(lang) {
133
                langs = append(langs, lang)
134
        }
135
        if lang := o.g.GetString(KeyLangs); utils.IsStrNotBlank(lang) {
136
                langs = append(langs, lang)
137
        }
138
        if len(langs) > 0 {
139
                ctx = SetLangs(ctx, langs)
140
        }
141
        return
142
}
func WatermillMetadata
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/context.go:

92
func WatermillMetadata(ctx context.Context) (metadata message.Metadata) {
93
        metadata = make(message.Metadata)
94
        if langs := GetLangs(ctx); langs != nil {
95
                marshaled, _ := json.Marshal(langs)
96
                metadata["langs"] = string(marshaled)
97
        }
98
        if userID := GetUserID(ctx); utils.IsStrNotBlank(userID) {
99
                metadata["user_id"] = userID
100
        }
101
        if traceID := GetTraceID(ctx); utils.IsStrNotBlank(traceID) {
102
                metadata["trace_id"] = traceID
103
        }
104
        if taskID := GetCronTaskID(ctx); utils.IsStrNotBlank(taskID) {
105
                metadata["cron_task_id"] = taskID
106
        }
107
        if taskName := GetCronTaskName(ctx); utils.IsStrNotBlank(taskName) {
108
                metadata["cron_task_name"] = taskName
109
        }
110
        if deadline, ok := ctx.Deadline(); ok {
111
                metadata["deadline"] = deadline.Format(time.RFC3339Nano)
112
                metadata["deadline_location"] = deadline.Location().String()
113
        }
114
        return
115
}
func SetCronTaskID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

37
func SetCronTaskID(ctx context.Context, val string) context.Context {
38
        return utils.SetCtxAny(ctx, KeyCronTaskID, val)
39
}
func SetLangs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

29
func SetLangs(ctx context.Context, val []string) context.Context {
30
        return utils.SetCtxAny(ctx, KeyLangs, val)
31
}
func SetUserID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/context/candy.go:

13
func SetUserID(ctx context.Context, val string) context.Context {
14
        return utils.SetCtxAny(ctx, KeyUserID, val)
15
}
Package Overview: github.com/wfusion/gofusion/cron 76.8%

Please select a function to see what's left for testing.

@277:9(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 13/13
asynqRouter.adaptAsynqHandlerFunc(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 13/13
asynqRouter.initServer(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 10/10
@208:26(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 9/9
Construct(...) github.com/wfusion/gofusion/cron/construct.go 100.0% 7/7
asynqRouter.shutdown(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 7/7
@377:27(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 7/7
@344:8(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 2/2
asynqRouter.initTrigger(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 2/2
asynqRouter.preEnqueueFunc(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqWrapper.MakeRedisClient(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqRouter.newTask(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqRouter.unformatTaskName(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
task.Name(...) github.com/wfusion/gofusion/cron/types.go 100.0% 1/1
asynqRouter.postEnqueueFunc(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqRouter.formatTaskName(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqRouter.formatLockKey(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
asynqRouter.gatewayMiddleware(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/cron/construct.go 100.0% 1/1
asynqRouter.format(...) github.com/wfusion/gofusion/cron/log.go 100.0% 1/1
asynqRouter.defaultQueue(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
@89:9(...) github.com/wfusion/gofusion/cron/construct.go 100.0% 1/1
@404:10(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
@409:10(...) github.com/wfusion/gofusion/cron/asynq.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/cron/construct.go 100.0% 1/1
@33:9(...) github.com/wfusion/gofusion/cron/construct.go 90.9% 10/11
@302:9(...) github.com/wfusion/gofusion/cron/asynq.go 90.9% 10/11
addInstance(...) github.com/wfusion/gofusion/cron/construct.go 86.7% 13/15
asynqRouter.info(...) github.com/wfusion/gofusion/cron/log.go 85.7% 6/7
asynqRouter.debug(...) github.com/wfusion/gofusion/cron/log.go 85.7% 6/7
asynqWrapper.getTaskExecuteInterval(...) github.com/wfusion/gofusion/cron/asynq.go 85.7% 6/7
asynqRouter.warn(...) github.com/wfusion/gofusion/cron/log.go 85.7% 6/7
asynqWrapper.GetConfigs(...) github.com/wfusion/gofusion/cron/asynq.go 84.6% 11/13
asynqRouter.releaseCronTaskLock(...) github.com/wfusion/gofusion/cron/asynq.go 83.9% 26/31
Use(...) github.com/wfusion/gofusion/cron/construct.go 80.0% 8/10
asynqRouter.Start(...) github.com/wfusion/gofusion/cron/asynq.go 80.0% 8/10
newAsynq(...) github.com/wfusion/gofusion/cron/asynq.go 78.8% 26/33
@429:9(...) github.com/wfusion/gofusion/cron/asynq.go 75.0% 9/12
asynqWrapper.getConfigs(...) github.com/wfusion/gofusion/cron/asynq.go 54.8% 17/31
asynqRouter.Handle(...) github.com/wfusion/gofusion/cron/asynq.go 50.0% 2/4
asynqRouter.Serve(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/12
@246:40(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/4
@391:9(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/2
@256:20(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/2
asynqRouter.Use(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/2
@451:9(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/1
@78:4(...) github.com/wfusion/gofusion/cron/construct.go 0.0% 0/1
asynqRouter.newAsynqTask(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/1
asynqRouter.adaptRouterHandlerFunc(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/1
asynqRouter.adaptMiddleware(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/1
task.ID(...) github.com/wfusion/gofusion/cron/types.go 0.0% 0/1
@243:19(...) github.com/wfusion/gofusion/cron/asynq.go 0.0% 0/1
task.Payload(...) github.com/wfusion/gofusion/cron/types.go 0.0% 0/1
task.RawMessage(...) github.com/wfusion/gofusion/cron/types.go 0.0% 0/1
func @277:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

277
func(task *asynq.Task, opts []asynq.Option) (err error) {
278
                // when locker is disabled, we cannot determine which message should be discarded
279
                if a.locker == nil {
280
                        return
281
                }
282
283
                taskName := a.unformatTaskName(task.Type())
284
                lockKey := a.formatLockKey(taskName)
285
                if err = a.locker.Lock(ctx, lockKey, lock.Expire(tolerantOfTimeNotSync), lock.ReentrantKey(a.id)); err == nil {
286
                        a.info(ctx, "pre enqueue task %s success", taskName)
287
                        return
288
                }
289
290
                err = utils.ErrIgnore(err, lock.ErrTimeout, lock.ErrContextDone)
291
                if err == nil {
292
                        a.debug(ctx, "pre enqueue discard task %s", taskName)
293
                        return errDiscardMessage
294
                }
295
296
                a.warn(ctx, "pre enqueue task %s failed: %s", taskName, err)
297
                return
298
        }
func asynqRouter.adaptAsynqHandlerFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

402
func (a *asynqRouter) adaptAsynqHandlerFunc(h any) asynq.HandlerFunc {
403
        if fn, ok := h.(routerHandleFunc); ok {
404
                return func(ctx context.Context, raw *asynq.Task) (err error) {
405
                        return fn(ctx, a.newTask(raw))
406
                }
407
        }
408
        if fn, ok := h.(func(ctx context.Context, task Task) (err error)); ok {
409
                return func(ctx context.Context, raw *asynq.Task) (err error) {
410
                        return fn(ctx, a.newTask(raw))
411
                }
412
        }
413
414
        var (
415
                hasArg          bool
416
                argType         reflect.Type
417
                argTypePtrDepth int
418
        )
419
        if reflect.TypeOf(h).NumIn() > 1 {
420
                argType = reflect.TypeOf(h).In(1)
421
                for argType.Kind() == reflect.Ptr {
422
                        argType = argType.Elem()
423
                        argTypePtrDepth++
424
                }
425
                hasArg = true
426
        }
427
428
        fn := utils.WrapFunc1[error](h)
429
        return func(ctx context.Context, raw *asynq.Task) (err error) {
430
                if !hasArg {
431
                        return fn(ctx)
432
                }
433
                arg := reflect.New(argType)
434
                payload := raw.Payload()
435
                if len(payload) == 0 {
436
                        payload = []byte("null")
437
                }
438
                if err = json.Unmarshal(payload, arg.Interface()); err != nil {
439
                        return
440
                }
441
                arg = arg.Elem()
442
                for i := 0; i < argTypePtrDepth; i++ {
443
                        arg = arg.Addr()
444
                }
445
446
                return fn(ctx, arg.Interface())
447
        }
448
}
func asynqRouter.initServer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

229
func (a *asynqRouter) initServer(ctx context.Context, wrapper *asynqWrapper, logLevel asynq.LogLevel) {
230
        a.ServeMux = asynq.NewServeMux()
231
        for pattern, taskCfg := range a.c.Tasks {
232
                if utils.IsStrBlank(taskCfg.Callback) {
233
                        continue
234
                }
235
                handler := *(*routerHandleFunc)(inspect.FuncOf(taskCfg.Callback))
236
                a.ServeMux.Handle(a.formatTaskName(pattern), a.adaptAsynqHandlerFunc(handler))
237
        }
238
239
        asynqCfg := asynq.Config{
240
                Concurrency:    a.c.ServerConcurrency,
241
                BaseContext:    context.Background,
242
                RetryDelayFunc: asynq.DefaultRetryDelayFunc,
243
                IsFailure:      func(err error) bool { return !errors.Is(err, errDiscardMessage) },
244
                Queues:         nil,
245
                StrictPriority: false,
246
                ErrorHandler: asynq.ErrorHandlerFunc(func(ctx context.Context, task *asynq.Task, err error) {
247
                        taskName := "unknown"
248
                        if task != nil {
249
                                taskName = a.unformatTaskName(task.Type())
250
                        }
251
                        a.info(ctx, "handle task %s message error %s", taskName, err)
252
                }),
253
                Logger:          a.logger,
254
                LogLevel:        logLevel,
255
                ShutdownTimeout: 8 * time.Second,
256
                HealthCheckFunc: func(err error) {
257
                        if err != nil {
258
                                a.warn(ctx, "health check check failed: %s", err)
259
                        }
260
                },
261
                HealthCheckInterval:      15 * time.Second,
262
                DelayedTaskCheckInterval: 5 * time.Second,
263
                GroupGracePeriod:         1 * time.Minute,
264
                GroupMaxDelay:            0,
265
                GroupMaxSize:             0,
266
                GroupAggregator:          nil,
267
                DisableRedisConnClose:    true,
268
        }
269
        if utils.IsStrNotBlank(a.c.Queue) {
270
                asynqCfg.Queues = map[string]int{a.c.Queue: 3}
271
        }
272
273
        a.server = asynq.NewServer(wrapper, asynqCfg)
274
}
func @208:26
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

208
func(task *asynq.Task, opts []asynq.Option, err error) {
209
                                        ignored := []error{errDiscardMessage}
210
                                        if a.locker == nil {
211
                                                ignored = append(ignored, asynq.ErrDuplicateTask, asynq.ErrTaskIDConflict)
212
                                        }
213
                                        if err = utils.ErrIgnore(err, ignored...); err == nil {
214
                                                return
215
                                        }
216
                                        taskName := "unknown"
217
                                        if task != nil {
218
                                                taskName = a.unformatTaskName(task.Type())
219
                                        }
220
                                        a.warn(ctx, "enqueue task %s failed: %s", taskName, err)
221
                                }
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

23
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
24
        opt := utils.ApplyOptions[config.InitOption](opts...)
25
        optU := utils.ApplyOptions[useOption](opts...)
26
        if opt.AppName == "" {
27
                opt.AppName = optU.appName
28
        }
29
30
        for name, conf := range confs {
31
                addInstance(ctx, name, conf, opt)
32
        }
33
        return func() {
34
                locker.Lock()
35
                defer locker.Unlock()
36
37
                pid := syscall.Getpid()
38
                app := config.Use(opt.AppName).AppName()
39
                if routers != nil {
40
                        for name, router := range routers[opt.AppName] {
41
                                log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentCron, name)
42
                                if err := router.shutdown(); err == nil {
43
                                        log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentCron, name)
44
                                } else {
45
                                        log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentCron, name, err)
46
                                }
47
                        }
48
                        delete(routers, opt.AppName)
49
                }
50
        }
51
}
func asynqRouter.shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

184
func (a *asynqRouter) shutdown() (err error) {
185
        if a.c.Trigger {
186
                _, catchErr := utils.Catch(a.trigger.Shutdown)
187
                err = multierr.Append(err, errors.Cause(catchErr))
188
        }
189
        if a.c.Server {
190
                _, catchErr := utils.Catch(a.server.Shutdown)
191
                err = multierr.Append(err, errors.Cause(catchErr))
192
        }
193
        return
194
}
func @377:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

377
func(ctx context.Context, raw *asynq.Task) (err error) {
378
                taskName := a.unformatTaskName(raw.Type())
379
                inspect.SetField(raw, asyncqTaskTypenameField, taskName)
380
                if utils.IsStrBlank(fusCtx.GetTraceID(ctx)) {
381
                        ctx = fusCtx.SetTraceID(ctx, utils.NginxID())
382
                }
383
                if utils.IsStrBlank(fusCtx.GetCronTaskName(ctx)) {
384
                        ctx = fusCtx.SetCronTaskName(ctx, taskName)
385
                }
386
                return next.ProcessTask(ctx, raw)
387
        }
func @344:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

344
func() {
345
                if e != nil {
346
                        a.warn(ctx, "post enqueue task %s release lock failed: %s", taskName, e)
347
                }
348
        }
func asynqRouter.initTrigger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

196
func (a *asynqRouter) initTrigger(ctx context.Context, wrapper *asynqWrapper, logLevel asynq.LogLevel) {
197
        a.trigger = utils.Must(
198
                asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{
199
                        PeriodicTaskConfigProvider: wrapper,
200
                        RedisConnOpt:               wrapper,
201
                        SchedulerOpts: &asynq.SchedulerOpts{
202
                                Logger:                a.logger,
203
                                LogLevel:              logLevel,
204
                                Location:              utils.Must(time.LoadLocation(a.c.Timezone)),
205
                                DisableRedisConnClose: true,
206
                                PreEnqueueFunc:        a.preEnqueueFunc(ctx),
207
                                PostEnqueueFunc:       a.postEnqueueFunc(ctx),
208
                                EnqueueErrorHandler: func(task *asynq.Task, opts []asynq.Option, err error) {
209
                                        ignored := []error{errDiscardMessage}
210
                                        if a.locker == nil {
211
                                                ignored = append(ignored, asynq.ErrDuplicateTask, asynq.ErrTaskIDConflict)
212
                                        }
213
                                        if err = utils.ErrIgnore(err, ignored...); err == nil {
214
                                                return
215
                                        }
216
                                        taskName := "unknown"
217
                                        if task != nil {
218
                                                taskName = a.unformatTaskName(task.Type())
219
                                        }
220
                                        a.warn(ctx, "enqueue task %s failed: %s", taskName, err)
221
                                },
222
                        },
223
                        SyncInterval: utils.Must(time.ParseDuration(a.c.RefreshTasksInterval)),
224
                }),
225
        )
226
        a.id = a.trigger.ID()
227
}
func asynqRouter.preEnqueueFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

276
func (a *asynqRouter) preEnqueueFunc(ctx context.Context) func(*asynq.Task, []asynq.Option) error {
277
        return func(task *asynq.Task, opts []asynq.Option) (err error) {
278
                // when locker is disabled, we cannot determine which message should be discarded
279
                if a.locker == nil {
280
                        return
281
                }
282
283
                taskName := a.unformatTaskName(task.Type())
284
                lockKey := a.formatLockKey(taskName)
285
                if err = a.locker.Lock(ctx, lockKey, lock.Expire(tolerantOfTimeNotSync), lock.ReentrantKey(a.id)); err == nil {
286
                        a.info(ctx, "pre enqueue task %s success", taskName)
287
                        return
288
                }
289
290
                err = utils.ErrIgnore(err, lock.ErrTimeout, lock.ErrContextDone)
291
                if err == nil {
292
                        a.debug(ctx, "pre enqueue discard task %s", taskName)
293
                        return errDiscardMessage
294
                }
295
296
                a.warn(ctx, "pre enqueue task %s failed: %s", taskName, err)
297
                return
298
        }
299
}
func asynqWrapper.MakeRedisClient
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

491
func (a *asynqWrapper) MakeRedisClient() any {
492
        return a.cli
493
}
func asynqRouter.newTask
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

469
func (a *asynqRouter) newTask(raw *asynq.Task) (t Task) {
470
        return &task{
471
                id:         raw.Type(),
472
                name:       raw.Type(),
473
                payload:    raw.Payload(),
474
                rawMessage: raw,
475
        }
476
}
func asynqRouter.unformatTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

465
func (a *asynqRouter) unformatTaskName(taskName string) (result string) {
466
        return strings.TrimPrefix(taskName, fmt.Sprintf("%s:cron:", config.Use(a.appName).AppName()))
467
}
func task.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/types.go:

97
func (t *task) Name() string {
98
        return t.name
99
}
func asynqRouter.postEnqueueFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

301
func (a *asynqRouter) postEnqueueFunc(ctx context.Context) func(info *asynq.TaskInfo, err error) {
302
        return func(info *asynq.TaskInfo, err error) {
303
                // release lock
304
                if a.locker != nil {
305
                        defer routine.Go(a.releaseCronTaskLock, routine.Args(ctx, info), routine.AppName(a.appName))
306
                }
307
308
                ignored := []error{errDiscardMessage}
309
                if a.locker == nil {
310
                        ignored = append(ignored, asynq.ErrDuplicateTask, asynq.ErrTaskIDConflict)
311
                }
312
313
                if err = utils.ErrIgnore(err, ignored...); err == nil {
314
                        return
315
                }
316
                taskName := "unknown"
317
                if info != nil {
318
                        taskName = a.unformatTaskName(info.Type)
319
                }
320
                a.debug(ctx, "post enqueue task %s failed: %s", taskName, err)
321
        }
322
}
func asynqRouter.formatTaskName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

462
func (a *asynqRouter) formatTaskName(taskName string) (result string) {
463
        return fmt.Sprintf("%s:cron:%s", config.Use(a.appName).AppName(), taskName)
464
}
func asynqRouter.formatLockKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

459
func (a *asynqRouter) formatLockKey(taskName string) string {
460
        return fmt.Sprintf("cron_%s", taskName)
461
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

593
func init() {
594
        rand.Seed(time.Now().UnixMicro())
595
}
func asynqRouter.gatewayMiddleware
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

376
func (a *asynqRouter) gatewayMiddleware(next asynq.Handler) asynq.Handler {
377
        return asynq.HandlerFunc(func(ctx context.Context, raw *asynq.Task) (err error) {
378
                taskName := a.unformatTaskName(raw.Type())
379
                inspect.SetField(raw, asyncqTaskTypenameField, taskName)
380
                if utils.IsStrBlank(fusCtx.GetTraceID(ctx)) {
381
                        ctx = fusCtx.SetTraceID(ctx, utils.NginxID())
382
                }
383
                if utils.IsStrBlank(fusCtx.GetCronTaskName(ctx)) {
384
                        ctx = fusCtx.SetCronTaskName(ctx, taskName)
385
                }
386
                return next.ProcessTask(ctx, raw)
387
        })
388
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

88
func AppName(name string) utils.OptionFunc[useOption] {
89
        return func(o *useOption) {
90
                o.appName = name
91
        }
92
}
func asynqRouter.format
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/log.go:

48
func (a *asynqRouter) format(src string) (dst string) {
49
        return fmt.Sprintf("%v [Gofusion] %s %s asynq(%s) %s",
50
                syscall.Getpid(), config.ComponentCron, a.n, a.id, src)
51
}
func asynqRouter.defaultQueue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

456
func (a *asynqRouter) defaultQueue() (result string) {
457
        return fmt.Sprintf("%s:cron", config.Use(a.appName).AppName())
458
}
func @89:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

89
func(o *useOption) {
90
                o.appName = name
91
        }
func @404:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

404
func(ctx context.Context, raw *asynq.Task) (err error) {
405
                        return fn(ctx, a.newTask(raw))
406
                }
func @409:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

409
func(ctx context.Context, raw *asynq.Task) (err error) {
410
                        return fn(ctx, a.newTask(raw))
411
                }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

111
func init() {
112
        config.AddComponent(config.ComponentCron, Construct)
113
}
func @33:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

33
func() {
34
                locker.Lock()
35
                defer locker.Unlock()
36
37
                pid := syscall.Getpid()
38
                app := config.Use(opt.AppName).AppName()
39
                if routers != nil {
40
                        for name, router := range routers[opt.AppName] {
41
                                log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentCron, name)
42
                                if err := router.shutdown(); err == nil {
43
                                        log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentCron, name)
44
                                } else {
45
                                        log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentCron, name, err)
46
                                }
47
                        }
48
                        delete(routers, opt.AppName)
49
                }
50
        }
func @302:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

302
func(info *asynq.TaskInfo, err error) {
303
                // release lock
304
                if a.locker != nil {
305
                        defer routine.Go(a.releaseCronTaskLock, routine.Args(ctx, info), routine.AppName(a.appName))
306
                }
307
308
                ignored := []error{errDiscardMessage}
309
                if a.locker == nil {
310
                        ignored = append(ignored, asynq.ErrDuplicateTask, asynq.ErrTaskIDConflict)
311
                }
312
313
                if err = utils.ErrIgnore(err, ignored...); err == nil {
314
                        return
315
                }
316
                taskName := "unknown"
317
                if info != nil {
318
                        taskName = a.unformatTaskName(info.Type)
319
                }
320
                a.debug(ctx, "post enqueue task %s failed: %s", taskName, err)
321
        }
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

53
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
54
        var r IRouter
55
        switch conf.Type {
56
        case schedulerTypeAsynq:
57
                r = newAsynq(ctx, opt.AppName, name, conf)
58
        default:
59
                panic(ErrUnsupportedSchedulerType)
60
        }
61
62
        locker.Lock()
63
        defer locker.Unlock()
64
        if routers == nil {
65
                routers = make(map[string]map[string]IRouter)
66
        }
67
        if routers[opt.AppName] == nil {
68
                routers[opt.AppName] = make(map[string]IRouter)
69
        }
70
        if _, ok := routers[opt.AppName][name]; ok {
71
                panic(errors.Errorf("duplicated cron name: %s", name))
72
        }
73
        routers[opt.AppName][name] = r
74
75
        // ioc
76
        if opt.DI != nil {
77
                opt.DI.MustProvide(
78
                        func() IRouter { return Use(name, AppName(opt.AppName)) },
79
                        di.Name(name),
80
                )
81
        }
82
}
func asynqRouter.info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/log.go:

24
func (a *asynqRouter) info(ctx context.Context, msg string, args ...any) {
25
        msg = a.format(msg)
26
        if a.logger == nil {
27
                log.Printf(msg, args...)
28
        } else {
29
                logArgs := make([]any, 0, len(args)+2)
30
                logArgs = append(logArgs, ctx, msg)
31
                logArgs = append(logArgs, args...)
32
                a.logger.Info(logArgs...)
33
        }
34
}
func asynqRouter.debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/log.go:

12
func (a *asynqRouter) debug(ctx context.Context, msg string, args ...any) {
13
        msg = a.format(msg)
14
        if a.logger == nil {
15
                log.Printf(msg, args...)
16
        } else {
17
                logArgs := make([]any, 0, len(args)+2)
18
                logArgs = append(logArgs, ctx, msg)
19
                logArgs = append(logArgs, args...)
20
                a.logger.Debug(logArgs...)
21
        }
22
}
func asynqWrapper.getTaskExecuteInterval
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

582
func (a *asynqWrapper) getTaskExecuteInterval(spec string) (interval time.Duration, err error) {
583
        now := time.Now()
584
        scheduler, err := cron.ParseStandard(spec)
585
        if err != nil {
586
                return 0, err
587
        }
588
        next := scheduler.Next(now)
589
        interval = scheduler.Next(next).Sub(next)
590
        return
591
}
func asynqRouter.warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/log.go:

36
func (a *asynqRouter) warn(ctx context.Context, msg string, args ...any) {
37
        msg = a.format(msg)
38
        if a.logger == nil {
39
                log.Printf(msg, args...)
40
        } else {
41
                logArgs := make([]any, 0, len(args)+2)
42
                logArgs = append(logArgs, ctx, msg)
43
                logArgs = append(logArgs, args...)
44
                a.logger.Warn(logArgs...)
45
        }
46
}
func asynqWrapper.GetConfigs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

495
func (a *asynqWrapper) GetConfigs() (result []*asynq.PeriodicTaskConfig, err error) {
496
        result, err = a.getConfigs()
497
        if err != nil {
498
                return
499
        }
500
501
        a.r.l.Lock()
502
        defer a.r.l.Unlock()
503
        for _, cfg := range result {
504
                // renaming
505
                taskName := inspect.GetField[string](cfg.Task, asyncqTaskTypenameField)
506
                inspect.SetField(cfg.Task, asyncqTaskTypenameField, a.r.formatTaskName(taskName))
507
508
                name := cfg.Task.Type()
509
                a.r.lockDurations[name], err = a.getTaskExecuteInterval(cfg.Cronspec)
510
                if err != nil {
511
                        return
512
                }
513
        }
514
515
        return
516
}
func asynqRouter.releaseCronTaskLock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

324
func (a *asynqRouter) releaseCronTaskLock(ctx context.Context, info *asynq.TaskInfo) {
325
        if info == nil {
326
                return
327
        }
328
        taskName := a.unformatTaskName(info.Type)
329
330
        // 90 ~ 100ms jitter
331
        jitter := 90*time.Millisecond + time.Duration(float64(10*time.Millisecond)*rand.Float64())
332
333
        a.l.RLock()
334
        lockTime := a.lockDurations[info.Type]
335
        a.l.RUnlock()
336
337
        // prevent a negative tolerant
338
        tolerant := utils.Min(tolerantOfTimeNotSync, lockTime) - jitter
339
        tolerant = utils.Max(tolerant, 500*time.Millisecond)
340
        timer := time.NewTimer(tolerant)
341
        defer timer.Stop()
342
343
        var e error
344
        defer func() {
345
                if e != nil {
346
                        a.warn(ctx, "post enqueue task %s release lock failed: %s", taskName, e)
347
                }
348
        }()
349
350
        now := time.Now()
351
        unlockKey := a.formatLockKey(taskName)
352
        for {
353
                select {
354
                case <-ctx.Done():
355
                        a.debug(ctx, "post enqueue task %s release lock: context done", taskName)
356
                        e = a.locker.Unlock(ctx, unlockKey, lock.ReentrantKey(a.id))
357
                        return
358
                case <-timer.C:
359
                        e = a.locker.Unlock(ctx, unlockKey, lock.ReentrantKey(a.id))
360
                        return
361
                default:
362
                        a.l.RLock()
363
                        newLockTime := a.lockDurations[info.Type]
364
                        a.l.RUnlock()
365
                        if newLockTime != lockTime {
366
                                lockTime = newLockTime
367
                                tolerant = utils.Min(tolerantOfTimeNotSync, lockTime) - jitter
368
                                tolerant = utils.Max(tolerant, 500*time.Millisecond)
369
                                tolerant = utils.Max(0, tolerant-time.Since(now))
370
                                timer.Reset(tolerant)
371
                        }
372
                }
373
        }
374
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

94
func Use(name string, opts ...utils.OptionExtender) IRouter {
95
        opt := utils.ApplyOptions[useOption](opts...)
96
97
        locker.RLock()
98
        defer locker.RUnlock()
99
        routers, ok := routers[opt.appName]
100
        if !ok {
101
                panic(errors.Errorf("cron router instance not found for app: %s", opt.appName))
102
        }
103
104
        router, ok := routers[name]
105
        if !ok {
106
                panic(errors.Errorf("cron router instance not found for name: %s", name))
107
        }
108
        return router
109
}
func asynqRouter.Start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

164
func (a *asynqRouter) Start() (err error) {
165
        defer a.info(context.Background(), "scheduler started")
166
167
        if a.c.Trigger {
168
                if err = a.trigger.Start(); err != nil {
169
                        return
170
                }
171
        }
172
173
        if a.c.Server {
174
                a.ServeMux.Use(a.gatewayMiddleware)
175
                a.ServeMux.Use(a.mws...)
176
                if err = a.server.Start(a.ServeMux); err != nil {
177
                        return
178
                }
179
        }
180
181
        return
182
}
func newAsynq
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

63
func newAsynq(ctx context.Context, appName, name string, conf *Conf) IRouter {
64
        r := &asynqRouter{
65
                appName:               appName,
66
                n:                     name,
67
                c:                     conf,
68
                lockDurations:         make(map[string]time.Duration, len(conf.Tasks)),
69
                shouldShutdownServer:  true,
70
                shouldShutdownTrigger: true,
71
        }
72
        if utils.IsStrBlank(r.c.Queue) {
73
                r.c.Queue = r.defaultQueue()
74
        }
75
76
        var rdsCli rdsDrv.UniversalClient
77
        switch conf.InstanceType {
78
        case instanceTypeRedis:
79
                rdsCli = redis.Use(ctx, conf.Instance, redis.AppName(appName))
80
        case instanceTypeMysql:
81
                fallthrough
82
        default:
83
                panic(errors.Errorf("unknown instance type: %s", conf.InstanceType))
84
        }
85
86
        if r.logger == nil && utils.IsStrNotBlank(conf.Logger) {
87
                loggerType := inspect.TypeOf(conf.Logger)
88
                loggerValue := reflect.New(loggerType)
89
                if loggerValue.Type().Implements(customLoggerType) {
90
                        logger := log.Use(conf.LogInstance, log.AppName(appName))
91
                        loggerValue.Interface().(customLogger).Init(logger, appName, name)
92
                }
93
                r.logger = loggerValue.Convert(asynqLoggerType).Interface().(asynq.Logger)
94
        }
95
        if r.locker == nil && utils.IsStrNotBlank(conf.LockInstance) {
96
                r.locker = lock.Use(conf.LockInstance, lock.AppName(appName))
97
                if r.locker == nil {
98
                        panic(errors.Errorf("locker instance not found: %s", conf.LockInstance))
99
                }
100
        }
101
102
        var provider asynq.PeriodicTaskConfigProvider
103
        if utils.IsStrNotBlank(conf.TaskLoader) {
104
                loaderType := inspect.TypeOf(conf.TaskLoader)
105
                if loaderType == nil {
106
                        panic(errors.Errorf("%s not found", conf.TaskLoader))
107
                }
108
                provider = reflect.New(loaderType).
109
                        Convert(asynqPeriodicTaskConfigProviderType).Interface().(asynq.PeriodicTaskConfigProvider)
110
        }
111
112
        logLevel := asynq.LogLevel(0)
113
        utils.MustSuccess(logLevel.Set(conf.LogLevel))
114
115
        wrapper := &asynqWrapper{r: r, n: r.n, appName: appName, cli: rdsCli, provider: provider}
116
        if conf.Trigger {
117
                r.initTrigger(ctx, wrapper, logLevel)
118
        }
119
        if conf.Server {
120
                r.initServer(ctx, wrapper, logLevel)
121
        }
122
123
        return r
124
}
func @429:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

429
func(ctx context.Context, raw *asynq.Task) (err error) {
430
                if !hasArg {
431
                        return fn(ctx)
432
                }
433
                arg := reflect.New(argType)
434
                payload := raw.Payload()
435
                if len(payload) == 0 {
436
                        payload = []byte("null")
437
                }
438
                if err = json.Unmarshal(payload, arg.Interface()); err != nil {
439
                        return
440
                }
441
                arg = arg.Elem()
442
                for i := 0; i < argTypePtrDepth; i++ {
443
                        arg = arg.Addr()
444
                }
445
446
                return fn(ctx, arg.Interface())
447
        }
func asynqWrapper.getConfigs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

518
func (a *asynqWrapper) getConfigs() (result []*asynq.PeriodicTaskConfig, err error) {
519
        if a.provider != nil {
520
                result, err = a.provider.GetConfigs()
521
                if err != nil {
522
                        return
523
                }
524
        }
525
526
        var confs map[string]*Conf
527
        if err = config.Use(a.appName).LoadComponentConfig(config.ComponentCron, &confs); err != nil {
528
                return
529
        }
530
        conf, ok := confs[a.n]
531
        if !ok {
532
                return nil, errors.Errorf("%s cron config not found", a.n)
533
        }
534
535
        loc, _ := time.LoadLocation(a.r.c.Timezone)
536
        if loc == nil {
537
                loc = constant.DefaultLocation()
538
        }
539
540
        queue := conf.Queue
541
        if utils.IsStrBlank(queue) {
542
                queue = a.r.c.Queue
543
        }
544
        for name, cfg := range conf.Tasks {
545
                var (
546
                        deadline          time.Time
547
                        interval, timeout time.Duration
548
                        opts              []asynq.Option
549
                )
550
                if interval, err = a.getTaskExecuteInterval(cfg.Crontab); err != nil {
551
                        return
552
                }
553
                if utils.IsStrNotBlank(cfg.Timeout) {
554
                        if timeout, err = time.ParseDuration(cfg.Timeout); err != nil {
555
                                return
556
                        }
557
                        opts = append(opts, asynq.Timeout(timeout))
558
                } else {
559
                        opts = append(opts, asynq.Timeout(interval))
560
                }
561
                if utils.IsStrNotBlank(cfg.Deadline) {
562
                        if deadline, err = time.ParseInLocation(constant.StdTimeLayout, cfg.Deadline, loc); err != nil {
563
                                return
564
                        }
565
                        opts = append(opts, asynq.Deadline(deadline))
566
                }
567
568
                result = append(result, &asynq.PeriodicTaskConfig{
569
                        Cronspec: cfg.Crontab,
570
                        Task:     asynq.NewTask(name, []byte(cfg.Payload)),
571
                        Opts: append(opts, []asynq.Option{
572
                                asynq.TaskID(name),
573
                                asynq.Unique(utils.Min(interval, tolerantOfTimeNotSync)),
574
                                asynq.Queue(queue),
575
                                asynq.MaxRetry(utils.Max(0, cfg.Retry)),
576
                        }...),
577
                })
578
        }
579
        return
580
}
func asynqRouter.Handle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

132
func (a *asynqRouter) Handle(pattern string, fn any, _ ...utils.OptionExtender) {
133
        if !a.c.Server {
134
                a.debug(context.Background(), "cannot handle task %s: client is not enabled", a.n)
135
                return
136
        }
137
138
        a.ServeMux.Handle(a.formatTaskName(pattern), a.adaptAsynqHandlerFunc(fn))
139
}
func asynqRouter.Serve
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

141
func (a *asynqRouter) Serve() (err error) {
142
        defer a.info(context.Background(), "scheduler is running")
143
144
        if a.c.Server {
145
                a.ServeMux.Use(a.gatewayMiddleware)
146
                a.ServeMux.Use(a.mws...)
147
        }
148
149
        if a.c.Trigger && !a.c.Server {
150
                return a.trigger.Run()
151
        }
152
        if !a.c.Trigger && a.c.Server {
153
                return a.server.Run(a.ServeMux)
154
        }
155
156
        a.shouldShutdownServer = false
157
        if err = a.trigger.Start(); err != nil {
158
                return
159
        }
160
161
        return a.server.Run(a.ServeMux)
162
}
func @246:40
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

246
func(ctx context.Context, task *asynq.Task, err error) {
247
                        taskName := "unknown"
248
                        if task != nil {
249
                                taskName = a.unformatTaskName(task.Type())
250
                        }
251
                        a.info(ctx, "handle task %s message error %s", taskName, err)
252
                }
func @391:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

391
func(asynqNext asynq.Handler) asynq.Handler {
392
                next := mw(a.adaptRouterHandlerFunc(asynqNext))
393
                return a.adaptAsynqHandlerFunc(next)
394
        }
func @256:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

256
func(err error) {
257
                        if err != nil {
258
                                a.warn(ctx, "health check check failed: %s", err)
259
                        }
260
                }
func asynqRouter.Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

126
func (a *asynqRouter) Use(mws ...routerMiddleware) {
127
        for _, mw := range mws {
128
                a.mws = append(a.mws, a.adaptMiddleware(mw))
129
        }
130
}
func @451:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

451
func(ctx context.Context, raw Task) (err error) {
452
                return h.ProcessTask(ctx, a.newAsynqTask(raw))
453
        }
func @78:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/construct.go:

78
func() IRouter { return Use(name, AppName(opt.AppName)) }
func asynqRouter.newAsynqTask
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

478
func (a *asynqRouter) newAsynqTask(raw Task) (t *asynq.Task) {
479
        return raw.RawMessage().(*asynq.Task)
480
}
func asynqRouter.adaptRouterHandlerFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

450
func (a *asynqRouter) adaptRouterHandlerFunc(h asynq.Handler) routerHandleFunc {
451
        return func(ctx context.Context, raw Task) (err error) {
452
                return h.ProcessTask(ctx, a.newAsynqTask(raw))
453
        }
454
}
func asynqRouter.adaptMiddleware
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

390
func (a *asynqRouter) adaptMiddleware(mw routerMiddleware) asynq.MiddlewareFunc {
391
        return func(asynqNext asynq.Handler) asynq.Handler {
392
                next := mw(a.adaptRouterHandlerFunc(asynqNext))
393
                return a.adaptAsynqHandlerFunc(next)
394
        }
395
}
func task.ID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/types.go:

93
func (t *task) ID() string {
94
        return t.id
95
}
func @243:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/asynq.go:

243
func(err error) bool { return !errors.Is(err, errDiscardMessage) }
func task.Payload
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/types.go:

101
func (t *task) Payload() []byte {
102
        return t.payload
103
}
func task.RawMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/cron/types.go:

105
func (t *task) RawMessage() any {
106
        return t.rawMessage
107
}
Package Overview: github.com/wfusion/gofusion/db 51.8%

Please select a function to see what's left for testing.

startDaemonRoutines(...) github.com/wfusion/gofusion/db/metrics.go 100.0% 10/10
Construct(...) github.com/wfusion/gofusion/db/construct.go 100.0% 9/9
.QueryFirst(...) github.com/wfusion/gofusion/db/dal.go 100.0% 7/7
@60:9(...) github.com/wfusion/gofusion/db/candy.go 100.0% 3/3
.unscopedGormDB(...) github.com/wfusion/gofusion/db/dal.go 100.0% 3/3
.InsertOne(...) github.com/wfusion/gofusion/db/dal.go 100.0% 3/3
@32:4(...) github.com/wfusion/gofusion/db/tx.go 100.0% 2/2
@16:23(...) github.com/wfusion/gofusion/db/ctx.go 100.0% 2/2
GetCtxGormDBByName(...) github.com/wfusion/gofusion/db/ctx.go 100.0% 2/2
ScanCursor(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
ScanBatch(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
@74:9(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
@17:9(...) github.com/wfusion/gofusion/db/tx.go 100.0% 1/1
TxUse(...) github.com/wfusion/gofusion/db/tx.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/db/db.go 100.0% 1/1
ScanDAL(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
Instance.GetProxy(...) github.com/wfusion/gofusion/db/db.go 100.0% 1/1
@406:46(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
@173:41(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
.Model(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
@40:41(...) github.com/wfusion/gofusion/db/tx.go 100.0% 1/1
@41:9(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
@68:9(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
@401:82(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
mysqlSoftDelete(...) github.com/wfusion/gofusion/db/construct.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/db/construct.go 100.0% 1/1
GetCtxGormDB(...) github.com/wfusion/gofusion/db/ctx.go 100.0% 1/1
ScanOrder(...) github.com/wfusion/gofusion/db/candy.go 100.0% 1/1
@46:9(...) github.com/wfusion/gofusion/db/db.go 100.0% 1/1
SetCtxGormDB(...) github.com/wfusion/gofusion/db/ctx.go 100.0% 1/1
Unscoped(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
@459:9(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
.CanIgnore(...) github.com/wfusion/gofusion/db/dal.go 100.0% 1/1
addInstance(...) github.com/wfusion/gofusion/db/construct.go 94.7% 36/38
adaptMysqlAutoIncrementIncrement(...) github.com/wfusion/gofusion/db/construct.go 88.9% 8/9
.Delete(...) github.com/wfusion/gofusion/db/dal.go 87.5% 14/16
@45:9(...) github.com/wfusion/gofusion/db/construct.go 86.7% 13/15
.ShardingIDGen(...) github.com/wfusion/gofusion/db/dal.go 83.3% 5/6
Use(...) github.com/wfusion/gofusion/db/db.go 80.0% 8/10
.parseOptionFromArgs(...) github.com/wfusion/gofusion/db/dal.go 80.0% 8/10
NewDAL(...) github.com/wfusion/gofusion/db/dal.go 80.0% 4/5
.InsertInBatches(...) github.com/wfusion/gofusion/db/dal.go 77.8% 7/9
WithinTx(...) github.com/wfusion/gofusion/db/tx.go 77.8% 7/9
.tableName(...) github.com/wfusion/gofusion/db/dal.go 77.8% 7/9
.writeWithTableSharding(...) github.com/wfusion/gofusion/db/dal.go 75.0% 9/12
.WriteDB(...) github.com/wfusion/gofusion/db/dal.go 75.0% 3/4
@116:21(...) github.com/wfusion/gofusion/db/metrics.go 73.9% 17/23
@58:21(...) github.com/wfusion/gofusion/db/metrics.go 73.5% 25/34
.Save(...) github.com/wfusion/gofusion/db/dal.go 71.4% 10/14
.ReadDB(...) github.com/wfusion/gofusion/db/dal.go 71.4% 5/7
Business.BeforeCreate(...) github.com/wfusion/gofusion/db/model.go 66.7% 4/6
metricDBStats(...) github.com/wfusion/gofusion/db/metrics.go 66.7% 2/3
.writeDB(...) github.com/wfusion/gofusion/db/dal.go 66.7% 2/3
metricDBLatency(...) github.com/wfusion/gofusion/db/metrics.go 66.7% 2/3
.IgnoreErr(...) github.com/wfusion/gofusion/db/dal.go 66.7% 2/3
Scan(...) github.com/wfusion/gofusion/db/candy.go 58.6% 34/58
BusinessSoftDeleted.BeforeCreate(...) github.com/wfusion/gofusion/db/model.go 57.1% 4/7
.convertAnyToTS(...) github.com/wfusion/gofusion/db/dal.go 50.0% 6/12
@206:9(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/16
@239:9(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/15
.ShardingByModelList(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/15
.ShardingIDListGen(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/12
.QueryInBatches(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/8
.Query(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/7
.Count(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/7
.QueryLast(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/7
.Transaction(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/7
.ShardingByValues(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/6
Data.Equals(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/5
Business.Equals(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/5
BusinessSoftDeleted.Equals(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/5
DataSoftDeleted.Equals(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/5
.Take(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/4
.Pluck(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/4
.Updates(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/4
.Update(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/4
.FirstOrCreate(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/4
.SetCtxWriteDB(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/3
.SetCtxReadDB(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/3
DataSoftDeleted.DeleteTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/3
BusinessSoftDeleted.Clone(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/3
Data.Clone(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/3
Business.Clone(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/3
@141:4(...) github.com/wfusion/gofusion/db/construct.go 0.0% 0/3
DataSoftDeleted.Clone(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/3
@53:9(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/2
@116:3(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/2
@33:4(...) github.com/wfusion/gofusion/db/tx.go 0.0% 0/2
@372:82(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
Data.ModifyTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
DataSoftDeleted.CreateTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
DataSoftDeleted.ModifyTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
Data.CreateTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@471:9(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
WriteDB(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
@465:9(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
Business.BeforeCreateFn(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@116:9(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
Business.BizCreateTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
Business.BizModifyTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
Clauses(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
@435:36(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
@379:56(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
BusinessSoftDeleted.BeforeCreateFn(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@170:9(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
.ModelSlice(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
BusinessSoftDeleted.BizModifyTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@273:74(...) github.com/wfusion/gofusion/db/dal.go 0.0% 0/1
@86:9(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
CheckGormErrorFn(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@204:58(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
JsonUnmarshalFn(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
@137:9(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
JsonMarshalFn(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
ScanLog(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
@80:9(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
ScanLimit(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
ScanWhere(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
@47:9(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
ScanUse(...) github.com/wfusion/gofusion/db/candy.go 0.0% 0/1
BusinessSoftDeleted.BizCreateTime(...) github.com/wfusion/gofusion/db/model.go 0.0% 0/1
func startDaemonRoutines
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/metrics.go:

28
func startDaemonRoutines(ctx context.Context, appName, name string, conf *Conf) {
29
        ticker := time.Tick(time.Second * 5)
30
        app := config.Use(appName).AppName()
31
        labels := []metrics.Label{
32
                {Key: "config", Value: name},
33
                {Key: "database", Value: conf.DB},
34
        }
35
36
        log.Printf("%v [Gofusion] %s %s %s metrics start", syscall.Getpid(), app, config.ComponentDB, name)
37
        for {
38
                select {
39
                case <-ctx.Done():
40
                        log.Printf("%v [Gofusion] %s %s %s metrics exited",
41
                                syscall.Getpid(), app, config.ComponentDB, name)
42
                        return
43
                case <-ticker:
44
                        go metricDBStats(ctx, appName, name, labels)
45
                        go metricDBLatency(ctx, appName, name, labels)
46
                }
47
        }
48
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

31
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
32
        opt := utils.ApplyOptions[config.InitOption](opts...)
33
        optU := utils.ApplyOptions[useOption](opts...)
34
        if opt.AppName == "" {
35
                opt.AppName = optU.appName
36
        }
37
38
        for name, conf := range confs {
39
                addInstance(ctx, name, conf, opt)
40
        }
41
        // patch delete at
42
        patches := make([]*gomonkey.Patches, 0, len(confs))
43
        patches = append(patches, softdelete.PatchGormDeleteAt())
44
45
        return func() {
46
                rwlock.Lock()
47
                defer rwlock.Unlock()
48
49
                pid := syscall.Getpid()
50
                app := config.Use(opt.AppName).AppName()
51
                if appInstances != nil {
52
                        for _, instance := range appInstances[opt.AppName] {
53
                                if sqlDB, err := instance.GetProxy().DB(); err == nil {
54
                                        if err := sqlDB.Close(); err != nil {
55
                                                log.Printf("%v [Gofusion] %s %s close error: %s", pid, app, config.ComponentDB, err)
56
                                        }
57
                                }
58
                        }
59
                        delete(appInstances, opt.AppName)
60
                }
61
                if len(appInstances) == 0 {
62
                        for _, patch := range patches {
63
                                if patch != nil {
64
                                        patch.Reset()
65
                                }
66
                        }
67
                        softdelete.PatchGormDeleteAtOnce = new(sync.Once)
68
                }
69
        }
70
}
func .QueryFirst
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

96
func (d *dal[T, TS]) QueryFirst(ctx context.Context, query any, args ...any) (*T, error) {
97
        o, args := d.parseOptionFromArgs(args...)
98
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
99
100
        found := d.Model()
101
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).First(found)
102
        if d.CanIgnore(result.Error) {
103
                return nil, nil
104
        }
105
        return found, d.IgnoreErr(result.Error)
106
}
func @60:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

60
func(o *scanOption) {
61
                o.cursors = cursors
62
                o.cursorWhere = cursorWhere
63
                o.cursorColumns = cursorColumns
64
        }
func .unscopedGormDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

445
func (d *dal[T, TS]) unscopedGormDB(src *gorm.DB, o *mysqlDALOption) (dst *gorm.DB) {
446
        if o != nil && o.unscoped {
447
                return src.Unscoped()
448
        }
449
        return src
450
}
func .InsertOne
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

161
func (d *dal[T, TS]) InsertOne(ctx context.Context, mod *T, opts ...utils.OptionExtender) error {
162
        o := utils.ApplyOptions[mysqlDALOption](opts...)
163
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
164
        return d.WriteDB(ctx).Clauses(o.clauses...).Create(mod).Error
165
}
func @32:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

32
func() bool { db = GetCtxGormDBByName(ctx, opt.dbName); return db != nil }
func @16:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/ctx.go:

16
func(ctx context.Context) bool {
17
                db = utils.GetCtxAny(ctx, fusCtx.KeyGormDB, (*DB)(nil))
18
                return db != nil && db.Name == name
19
        }
func GetCtxGormDBByName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/ctx.go:

15
func GetCtxGormDBByName(ctx context.Context, name string) (db *DB) {
16
        utils.TravelCtx(ctx, func(ctx context.Context) bool {
17
                db = utils.GetCtxAny(ctx, fusCtx.KeyGormDB, (*DB)(nil))
18
                return db != nil && db.Name == name
19
        })
20
        return
21
}
func ScanCursor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

59
func ScanCursor(cursorWhere any, cursorColumns []string, cursors ...any) utils.OptionFunc[scanOption] {
60
        return func(o *scanOption) {
61
                o.cursors = cursors
62
                o.cursorWhere = cursorWhere
63
                o.cursorColumns = cursorColumns
64
        }
65
}
func ScanBatch
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

73
func ScanBatch(batch int) utils.OptionFunc[scanOption] {
74
        return func(o *scanOption) {
75
                o.batch = batch
76
        }
77
}
func @74:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

74
func(o *scanOption) {
75
                o.batch = batch
76
        }
func @17:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

17
func(o *txOption) {
18
                o.dbName = name
19
        }
func TxUse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

16
func TxUse(name string) utils.OptionFunc[txOption] {
17
        return func(o *txOption) {
18
                o.dbName = name
19
        }
20
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/db.go:

45
func AppName(name string) utils.OptionFunc[useOption] {
46
        return func(o *useOption) {
47
                o.appName = name
48
        }
49
}
func ScanDAL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

40
func ScanDAL[T any, TS ~[]*T](dal DalInterface[T, TS]) utils.OptionFunc[scanOptionGeneric[T, TS]] {
41
        return func(o *scanOptionGeneric[T, TS]) {
42
                o.dal = dal
43
        }
44
}
func Instance.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/db.go:

31
func (d *Instance) GetProxy() *gorm.DB {
32
        return d.db.GetProxy()
33
}
func @406:46
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

406
func(t any) *T { return t.(*T) }
func @173:41
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

173
func(s string) bool { return strings.EqualFold(s, col) }
func .Model
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

316
func (d *dal[T, TS]) Model() *T      { return new(T) }
func @40:41
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

40
func(tx *gorm.DB) error {
41
                return cb(SetCtxGormDB(ctx, &DB{
42
                        DB:                   &orm.DB{DB: tx},
43
                        Name:                 db.Name,
44
                        tableShardingPlugins: db.tableShardingPlugins,
45
                }))
46
        }
func @41:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

41
func(o *scanOptionGeneric[T, TS]) {
42
                o.dal = dal
43
        }
func @68:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

68
func(o *scanOption) {
69
                o.order = order
70
        }
func @401:82
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

401
func(t *T) any { return t }
func mysqlSoftDelete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

178
func mysqlSoftDelete(db *orm.DB, conf *Conf) {
179
        callbacks.SoftDelete(db.GetProxy())
180
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

182
func init() {
183
        config.AddComponent(config.ComponentDB, Construct)
184
}
func GetCtxGormDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/ctx.go:

11
func GetCtxGormDB(ctx context.Context) *DB {
12
        return utils.GetCtxAny(ctx, fusCtx.KeyGormDB, (*DB)(nil))
13
}
func ScanOrder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

67
func ScanOrder(order any) utils.OptionFunc[scanOption] {
68
        return func(o *scanOption) {
69
                o.order = order
70
        }
71
}
func @46:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/db.go:

46
func(o *useOption) {
47
                o.appName = name
48
        }
func SetCtxGormDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/ctx.go:

23
func SetCtxGormDB(ctx context.Context, db *DB) context.Context {
24
        return utils.SetCtxAny(ctx, fusCtx.KeyGormDB, db)
25
}
func Unscoped
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

458
func Unscoped() utils.OptionFunc[mysqlDALOption] {
459
        return func(m *mysqlDALOption) {
460
                m.unscoped = true
461
        }
462
}
func @459:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

459
func(m *mysqlDALOption) {
460
                m.unscoped = true
461
        }
func .CanIgnore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

324
func (d *dal[T, TS]) CanIgnore(err error) bool { return errors.Is(err, gorm.ErrRecordNotFound) }
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

72
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
73
        var logObj logger.Interface
74
        if !config.Use(opt.AppName).Debug() && utils.IsStrNotBlank(conf.LoggerConfig.Logger) {
75
                loggerType := inspect.TypeOf(conf.LoggerConfig.Logger)
76
                loggerValue := reflect.New(loggerType)
77
                if loggerValue.Type().Implements(customLoggerType) {
78
                        l := fusLog.Use(conf.LoggerConfig.LogInstance, fusLog.AppName(opt.AppName))
79
                        loggerValue.Interface().(customLogger).Init(l, opt.AppName, name)
80
                }
81
                logObj = loggerValue.Interface().(logger.Interface)
82
        }
83
84
        // conf.Option.Password = config.CryptoDecryptFunc()(conf.Option.Password)
85
        db, err := orm.Gorm.New(ctx, conf.Option, orm.WithLogger(logObj))
86
        if err != nil {
87
                panic(errors.Errorf("initialize gorm db instance error: %+v", err))
88
        }
89
90
        adaptMysqlAutoIncrementIncrement(db, conf)
91
        mysqlSoftDelete(db, conf)
92
        if config.Use(opt.AppName).Debug() {
93
                db.DB = db.Debug()
94
        }
95
96
        // sharding
97
        tablePluginMap := make(map[string]plugins.TableSharding, len(conf.Sharding))
98
        for _, shardConf := range conf.Sharding {
99
                var generator idgen.Generator
100
                if utils.IsStrNotBlank(shardConf.IDGen) {
101
                        generator = (*(*func() idgen.Generator)(inspect.FuncOf(shardConf.IDGen)))()
102
                }
103
104
                var expression gval.Evaluable
105
                if utils.IsStrNotBlank(shardConf.ShardingKeyExpr) {
106
                        expression = utils.Must(gval.Full().NewEvaluable(shardConf.ShardingKeyExpr))
107
                }
108
109
                tableShardingPlugin := plugins.DefaultTableSharding(plugins.TableShardingConfig{
110
                        Database:                 name,
111
                        Table:                    shardConf.Table,
112
                        ShardingKeys:             shardConf.Columns,
113
                        ShardingKeyExpr:          expression,
114
                        ShardingKeyByRawValue:    shardConf.ShardingKeyByRawValue,
115
                        ShardingKeysForMigrating: shardConf.ShardingKeysForMigrating,
116
                        NumberOfShards:           shardConf.NumberOfShards,
117
                        CustomSuffix:             shardConf.Suffix,
118
                        PrimaryKeyGenerator:      generator,
119
                })
120
121
                utils.MustSuccess(db.Use(tableShardingPlugin))
122
                tablePluginMap[shardConf.Table] = tableShardingPlugin
123
        }
124
125
        rwlock.Lock()
126
        defer rwlock.Unlock()
127
        if appInstances == nil {
128
                appInstances = make(map[string]map[string]*Instance)
129
        }
130
        if appInstances[opt.AppName] == nil {
131
                appInstances[opt.AppName] = make(map[string]*Instance)
132
        }
133
        if _, ok := appInstances[opt.AppName][name]; ok {
134
                panic(ErrDuplicatedName)
135
        }
136
        appInstances[opt.AppName][name] = &Instance{db: db, name: name, tableShardingPlugins: tablePluginMap}
137
138
        // ioc
139
        if opt.DI != nil {
140
                opt.DI.MustProvide(
141
                        func() *gorm.DB {
142
                                rwlock.RLock()
143
                                defer rwlock.RUnlock()
144
                                return appInstances[opt.AppName][name].GetProxy()
145
                        },
146
                        di.Name(name),
147
                )
148
        }
149
150
        go startDaemonRoutines(ctx, opt.AppName, name, conf)
151
}
func adaptMysqlAutoIncrementIncrement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

155
func adaptMysqlAutoIncrementIncrement(db *orm.DB, conf *Conf) {
156
        autoIncrIncr := conf.AutoIncrementIncrement
157
        // unset, query auto increment increment
158
        if autoIncrIncr == 0 && conf.Driver == orm.DriverMysql {
159
                type autoConfig struct {
160
                        VariableName string `gorm:"column:Variable_name"`
161
                        Value        int64  `gorm:"column:Value"`
162
                }
163
164
                var cfg *autoConfig
165
                db.WithContext(context.Background()).
166
                        Raw("show variables like 'auto_increment_increment'").
167
                        Scan(&cfg)
168
                autoIncrIncr = cfg.Value
169
        }
170
        // no need to replace callbacks
171
        if autoIncrIncr <= 1 {
172
                return
173
        }
174
175
        callbacks.CreateAutoIncr(db.GetProxy(), db.GetDialector(), autoIncrIncr)
176
}
func .Delete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

237
func (d *dal[T, TS]) Delete(ctx context.Context, query any, args ...any) (int64, error) {
238
        o, args := d.parseOptionFromArgs(args...)
239
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
240
        mList, ok := d.convertAnyToTS(query)
241
        if !ok || len(mList) == 0 {
242
                deleted := d.WriteDB(ctx).Clauses(o.clauses...).Where(query, args...).Delete(d.Model())
243
                return deleted.RowsAffected, deleted.Error
244
        } else {
245
                sharded, err := d.writeWithTableSharding(ctx, mList)
246
                if err != nil {
247
                        return 0, err
248
                }
249
                var rowAffected int64
250
                for _, mList := range sharded {
251
                        deleted := d.WriteDB(ctx).Clauses(o.clauses...).Delete(mList, args...)
252
                        if deleted.Error != nil {
253
                                return rowAffected, deleted.Error
254
                        }
255
                        rowAffected += deleted.RowsAffected
256
                }
257
                return rowAffected, nil
258
        }
259
}
func @45:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

45
func() {
46
                rwlock.Lock()
47
                defer rwlock.Unlock()
48
49
                pid := syscall.Getpid()
50
                app := config.Use(opt.AppName).AppName()
51
                if appInstances != nil {
52
                        for _, instance := range appInstances[opt.AppName] {
53
                                if sqlDB, err := instance.GetProxy().DB(); err == nil {
54
                                        if err := sqlDB.Close(); err != nil {
55
                                                log.Printf("%v [Gofusion] %s %s close error: %s", pid, app, config.ComponentDB, err)
56
                                        }
57
                                }
58
                        }
59
                        delete(appInstances, opt.AppName)
60
                }
61
                if len(appInstances) == 0 {
62
                        for _, patch := range patches {
63
                                if patch != nil {
64
                                        patch.Reset()
65
                                }
66
                        }
67
                        softdelete.PatchGormDeleteAtOnce = new(sync.Once)
68
                }
69
        }
func .ShardingIDGen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

336
func (d *dal[T, TS]) ShardingIDGen(ctx context.Context) (id uint64, err error) {
337
        writeDB := d.writeDB(ctx)
338
        tableName := d.tableName(writeDB, new(T))
339
        tableShardingPlugin, ok := writeDB.tableShardingPlugins[tableName]
340
        if !ok {
341
                return 0, plugins.ErrIDGeneratorNotFound
342
        }
343
        return tableShardingPlugin.ShardingIDGen(ctx)
344
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/db.go:

51
func Use(ctx context.Context, name string, opts ...utils.OptionExtender) *DB {
52
        opt := utils.ApplyOptions[useOption](opts...)
53
54
        rwlock.RLock()
55
        defer rwlock.RUnlock()
56
        instances, ok := appInstances[opt.appName]
57
        if !ok {
58
                panic(errors.Errorf("db instance not found for app: %s", opt.appName))
59
        }
60
        instance, ok := instances[name]
61
        if !ok {
62
                panic(errors.Errorf("db instance not found for name: %s", name))
63
        }
64
65
        return &DB{DB: instance.db.WithContext(ctx), Name: name, tableShardingPlugins: instance.tableShardingPlugins}
66
}
func .parseOptionFromArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

476
func (d *dal[T, TS]) parseOptionFromArgs(args ...any) (o *mysqlDALOption, r []any) {
477
        o = new(mysqlDALOption)
478
        r = make([]any, 0, len(args))
479
        for _, arg := range args {
480
                if reflect.TypeOf(arg).Implements(gormClauseExpressionType) {
481
                        o.clauses = append(o.clauses, arg.(clause.Expression))
482
                        continue
483
                }
484
485
                switch v := arg.(type) {
486
                case utils.OptionFunc[mysqlDALOption]:
487
                        v(o)
488
                default:
489
                        r = append(r, arg)
490
                }
491
        }
492
        return
493
}
func NewDAL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

58
func NewDAL[T any, TS ~[]*T](readDBName, writeDBName string, opts ...utils.OptionExtender) DalInterface[T, TS] {
59
        instance := new(T)
60
        if _, ok := any(instance).(schema.Tabler); !ok {
61
                panic(errors.Errorf("model unimplement schema.Tabler [model[%T] read_db[%s] write_db[%s]]",
62
                        instance, readDBName, writeDBName))
63
        }
64
        opt := utils.ApplyOptions[useOption](opts...)
65
        return &dal[T, TS]{
66
                appName:     opt.appName,
67
                readDBName:  readDBName,
68
                writeDBName: writeDBName,
69
        }
70
}
func .InsertInBatches
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

167
func (d *dal[T, TS]) InsertInBatches(ctx context.Context,
168
        modList TS, batchSize int, opts ...utils.OptionExtender) error {
169
        o := utils.ApplyOptions[mysqlDALOption](opts...)
170
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
171
        sharded, err := d.writeWithTableSharding(ctx, modList)
172
        if err != nil {
173
                return err
174
        }
175
        for _, mList := range sharded {
176
                if err = d.WriteDB(ctx).Clauses(o.clauses...).CreateInBatches(mList, batchSize).Error; err != nil {
177
                        return err
178
                }
179
        }
180
181
        return nil
182
}
func WithinTx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

23
func WithinTx(ctx context.Context, cb func(ctx context.Context) (err error), opts ...utils.OptionExtender) error {
24
        var db *DB
25
26
        o := utils.ApplyOptions[useOption](opts...)
27
        opt := utils.ApplyOptions[txOption](opts...)
28
        if opt.dbName == "" {
29
                db = GetCtxGormDB(ctx)
30
        } else {
31
                utils.IfAny(
32
                        func() bool { db = GetCtxGormDBByName(ctx, opt.dbName); return db != nil },
33
                        func() bool { db = Use(ctx, opt.dbName, AppName(o.appName)); return db != nil },
34
                )
35
        }
36
        if db == nil {
37
                panic(ErrDatabaseNotFound)
38
        }
39
40
        return db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
41
                return cb(SetCtxGormDB(ctx, &DB{
42
                        DB:                   &orm.DB{DB: tx},
43
                        Name:                 db.Name,
44
                        tableShardingPlugins: db.tableShardingPlugins,
45
                }))
46
        })
47
}
func .tableName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

410
func (d *dal[T, TS]) tableName(db *DB, mod *T) (name string) {
411
        if tabler, ok := any(mod).(schema.Tabler); ok {
412
                name = tabler.TableName()
413
        }
414
        if tabler, ok := any(mod).(schema.TablerWithNamer); ok {
415
                name = tabler.TableName(db.NamingStrategy)
416
        }
417
        // TODO: check if embeddedNamer valid
418
        embeddedNamer := inspect.TypeOf("gorm.io/gorm/schema.embeddedNamer")
419
        namingStrategy := reflect.ValueOf(db.NamingStrategy)
420
        if namingStrategy.CanConvert(embeddedNamer) {
421
                name = namingStrategy.Convert(embeddedNamer).FieldByName("Table").String()
422
        }
423
        return
424
}
func .writeWithTableSharding
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

391
func (d *dal[T, TS]) writeWithTableSharding(ctx context.Context, src TS) (dst []TS, err error) {
392
        if len(src) == 0 {
393
                return
394
        }
395
        writeDB := d.writeDB(ctx)
396
        shardingPlugin, ok := writeDB.tableShardingPlugins[d.tableName(writeDB, src[0])]
397
        if !ok {
398
                return []TS{src}, nil
399
        }
400
401
        sharded, err := shardingPlugin.ShardingByModelList(ctx, utils.SliceMapping(src, func(t *T) any { return t })...)
402
        if err != nil {
403
                return
404
        }
405
        for _, item := range sharded {
406
                dst = append(dst, utils.SliceMapping(item, func(t any) *T { return t.(*T) }))
407
        }
408
        return
409
}
func .WriteDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

294
func (d *dal[T, TS]) WriteDB(ctx context.Context) *gorm.DB {
295
        o, _ := ctx.Value(fusCtx.KeyDALOption).(*mysqlDALOption)
296
        if orm := GetCtxGormDB(ctx); orm != nil && orm.Name == d.writeDBName {
297
                return d.unscopedGormDB(orm.Model(d.Model()), o)
298
        }
299
300
        return d.unscopedGormDB(Use(ctx, d.writeDBName, AppName(d.appName)).WithContext(ctx).Model(d.Model()), o)
301
}
func @116:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/metrics.go:

116
func() {
117
                rwlock.RLock()
118
                defer rwlock.RUnlock()
119
                instances, ok := appInstances[appName]
120
                if !ok {
121
                        return
122
                }
123
                instance, ok := instances[name]
124
                if !ok {
125
                        return
126
                }
127
                db := instance.GetProxy()
128
                sqlDB, err := db.DB()
129
                if err != nil {
130
                        return
131
                }
132
133
                begin := time.Now()
134
                if err := sqlDB.Ping(); err != nil {
135
                        return
136
                }
137
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
138
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
139
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
140
                        select {
141
                        case <-ctx.Done():
142
                                return
143
                        default:
144
                                if m.IsEnableServiceLabel() {
145
                                        m.AddSample(ctx, latencyKey, latency,
146
                                                metrics.Labels(labels),
147
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
148
                                        )
149
                                } else {
150
                                        m.AddSample(ctx, metricsLatencyKey, latency,
151
                                                metrics.Labels(labels),
152
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
153
                                        )
154
                                }
155
                        }
156
                }
157
        }
func @58:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/metrics.go:

58
func() {
59
                rwlock.RLock()
60
                defer rwlock.RUnlock()
61
62
                instances, ok := appInstances[appName]
63
                if !ok {
64
                        return
65
                }
66
                instance, ok := instances[name]
67
                if !ok {
68
                        return
69
                }
70
                db := instance.GetProxy()
71
                sqlDB, err := db.DB()
72
                if err != nil {
73
                        return
74
                }
75
76
                app := config.Use(appName).AppName()
77
                idleKey := append([]string{app}, metricsPoolIdleKey...)
78
                inuseKey := append([]string{app}, metricsPoolInUseKey...)
79
                totalKey := append([]string{app}, metricsPoolTotalKey...)
80
                waitCountKey := append([]string{app}, metricsPoolWaitCountKey...)
81
                waitDurationKey := append([]string{app}, metricsPoolWaitDurationKey...)
82
83
                stats := sqlDB.Stats()
84
                waitDuration := float64(stats.WaitDuration) / float64(time.Millisecond)
85
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
86
                        select {
87
                        case <-ctx.Done():
88
                                return
89
                        default:
90
                                if m.IsEnableServiceLabel() {
91
                                        m.SetGauge(ctx, idleKey, float64(stats.Idle), metrics.Labels(labels))
92
                                        m.SetGauge(ctx, inuseKey, float64(stats.InUse), metrics.Labels(labels))
93
                                        m.SetGauge(ctx, totalKey, float64(stats.OpenConnections), metrics.Labels(labels))
94
                                        m.SetGauge(ctx, waitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
95
                                        m.SetGauge(ctx, waitDurationKey, waitDuration, metrics.Labels(labels))
96
                                } else {
97
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(stats.Idle), metrics.Labels(labels))
98
                                        m.SetGauge(ctx, metricsPoolInUseKey, float64(stats.InUse), metrics.Labels(labels))
99
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(stats.OpenConnections), metrics.Labels(labels))
100
                                        m.SetGauge(ctx, metricsPoolWaitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
101
                                        m.SetGauge(ctx, metricsPoolWaitDurationKey, waitDuration, metrics.Labels(labels))
102
                                }
103
                        }
104
                }
105
        }
func .Save
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

197
func (d *dal[T, TS]) Save(ctx context.Context, mod any, opts ...utils.OptionExtender) error {
198
        // Translate the struct to slice to follow the insert into with ON DUPLICATE KEY UPDATE
199
        mList, ok := d.convertAnyToTS(mod)
200
        if !ok {
201
                mList = utils.SliceConvert(mod, reflect.TypeOf(TS{})).(TS)
202
        }
203
        if len(mList) == 0 {
204
                return nil
205
        }
206
        o := utils.ApplyOptions[mysqlDALOption](opts...)
207
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
208
        sharded, err := d.writeWithTableSharding(ctx, mList)
209
        if err != nil {
210
                return err
211
        }
212
        for _, mList := range sharded {
213
                if err = d.WriteDB(ctx).Clauses(o.clauses...).Save(mList).Error; err != nil {
214
                        return err
215
                }
216
        }
217
218
        return nil
219
}
func .ReadDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

282
func (d *dal[T, TS]) ReadDB(ctx context.Context) *gorm.DB {
283
        o, _ := ctx.Value(fusCtx.KeyDALOption).(*mysqlDALOption)
284
        if orm := GetCtxGormDB(ctx); orm != nil && orm.Name == d.readDBName {
285
                return d.unscopedGormDB(orm.Model(d.Model()), o)
286
        }
287
288
        dbName := d.readDBName
289
        if o != nil && o.useWriteDB {
290
                dbName = d.writeDBName
291
        }
292
        return d.unscopedGormDB(Use(ctx, dbName, AppName(d.appName)).WithContext(ctx).Model(d.Model()), o)
293
}
func Business.BeforeCreate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

105
func (b *Business) BeforeCreate(tx *gorm.DB) (err error) {
106
        if b == nil {
107
                tx.Statement.SetColumn("uuid", utils.UUID())
108
                return
109
        }
110
        if b.UUID == [16]byte{0} {
111
                b.UUID = uuid.New()
112
        }
113
        return
114
}
func metricDBStats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/metrics.go:

50
func metricDBStats(ctx context.Context, appName, name string, labels []metrics.Label) {
51
        select {
52
        case <-ctx.Done():
53
                return
54
        default:
55
56
        }
57
58
        _, _ = utils.Catch(func() {
59
                rwlock.RLock()
60
                defer rwlock.RUnlock()
61
62
                instances, ok := appInstances[appName]
63
                if !ok {
64
                        return
65
                }
66
                instance, ok := instances[name]
67
                if !ok {
68
                        return
69
                }
70
                db := instance.GetProxy()
71
                sqlDB, err := db.DB()
72
                if err != nil {
73
                        return
74
                }
75
76
                app := config.Use(appName).AppName()
77
                idleKey := append([]string{app}, metricsPoolIdleKey...)
78
                inuseKey := append([]string{app}, metricsPoolInUseKey...)
79
                totalKey := append([]string{app}, metricsPoolTotalKey...)
80
                waitCountKey := append([]string{app}, metricsPoolWaitCountKey...)
81
                waitDurationKey := append([]string{app}, metricsPoolWaitDurationKey...)
82
83
                stats := sqlDB.Stats()
84
                waitDuration := float64(stats.WaitDuration) / float64(time.Millisecond)
85
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
86
                        select {
87
                        case <-ctx.Done():
88
                                return
89
                        default:
90
                                if m.IsEnableServiceLabel() {
91
                                        m.SetGauge(ctx, idleKey, float64(stats.Idle), metrics.Labels(labels))
92
                                        m.SetGauge(ctx, inuseKey, float64(stats.InUse), metrics.Labels(labels))
93
                                        m.SetGauge(ctx, totalKey, float64(stats.OpenConnections), metrics.Labels(labels))
94
                                        m.SetGauge(ctx, waitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
95
                                        m.SetGauge(ctx, waitDurationKey, waitDuration, metrics.Labels(labels))
96
                                } else {
97
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(stats.Idle), metrics.Labels(labels))
98
                                        m.SetGauge(ctx, metricsPoolInUseKey, float64(stats.InUse), metrics.Labels(labels))
99
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(stats.OpenConnections), metrics.Labels(labels))
100
                                        m.SetGauge(ctx, metricsPoolWaitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
101
                                        m.SetGauge(ctx, metricsPoolWaitDurationKey, waitDuration, metrics.Labels(labels))
102
                                }
103
                        }
104
                }
105
        })
106
}
func .writeDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

384
func (d *dal[T, TS]) writeDB(ctx context.Context) *DB {
385
        if orm := GetCtxGormDB(ctx); orm != nil && orm.Name == d.writeDBName {
386
                return orm
387
        }
388
389
        return Use(ctx, d.writeDBName, AppName(d.appName))
390
}
func metricDBLatency
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/metrics.go:

108
func metricDBLatency(ctx context.Context, appName, name string, labels []metrics.Label) {
109
        select {
110
        case <-ctx.Done():
111
                return
112
        default:
113
114
        }
115
116
        _, _ = utils.Catch(func() {
117
                rwlock.RLock()
118
                defer rwlock.RUnlock()
119
                instances, ok := appInstances[appName]
120
                if !ok {
121
                        return
122
                }
123
                instance, ok := instances[name]
124
                if !ok {
125
                        return
126
                }
127
                db := instance.GetProxy()
128
                sqlDB, err := db.DB()
129
                if err != nil {
130
                        return
131
                }
132
133
                begin := time.Now()
134
                if err := sqlDB.Ping(); err != nil {
135
                        return
136
                }
137
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
138
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
139
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
140
                        select {
141
                        case <-ctx.Done():
142
                                return
143
                        default:
144
                                if m.IsEnableServiceLabel() {
145
                                        m.AddSample(ctx, latencyKey, latency,
146
                                                metrics.Labels(labels),
147
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
148
                                        )
149
                                } else {
150
                                        m.AddSample(ctx, metricsLatencyKey, latency,
151
                                                metrics.Labels(labels),
152
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
153
                                        )
154
                                }
155
                        }
156
                }
157
        })
158
}
func .IgnoreErr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

318
func (d *dal[T, TS]) IgnoreErr(err error) error {
319
        if errors.Is(err, gorm.ErrRecordNotFound) {
320
                return nil
321
        }
322
        return err
323
}
func Scan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

91
func Scan[T any, TS ~[]*T](ctx context.Context, cb func(TS) bool, opts ...utils.OptionExtender) (err error) {
92
        var (
93
                tx    *gorm.DB
94
                mList TS
95
        )
96
97
        o := utils.ApplyOptions[useOption](opts...)
98
        opt := utils.ApplyOptions[scanOption](opts...)
99
        optG := utils.ApplyOptions[scanOptionGeneric[T, TS]](opts...)
100
101
        // get db instance
102
        switch {
103
        case optG.dal != nil:
104
                tx = optG.dal.ReadDB(ctx)
105
        case opt.dbName != "":
106
                tx = Use(ctx, opt.dbName, AppName(o.appName)).GetProxy()
107
        default:
108
                panic(errors.New("unknown which table to scan"))
109
        }
110
111
        // default values
112
        if opt.cursors == nil {
113
                opt.cursors = []any{0}
114
        }
115
        if opt.cursorWhere == nil {
116
                opt.cursorWhere = "id > ?"
117
        }
118
        if len(opt.cursorColumns) == 0 {
119
                opt.cursorColumns = []string{"id"}
120
        }
121
        if opt.order == nil {
122
                opt.order = fmt.Sprintf("%s ASC", strings.Join(opt.cursorColumns, constant.Comma))
123
        }
124
        if opt.batch == 0 {
125
                opt.batch = 100
126
        }
127
        if opt.limit == 0 {
128
                opt.limit = math.MaxInt
129
        }
130
131
        count := 0
132
        tx = tx.WithContext(ctx)
133
        if opt.log != nil {
134
                opt.log.Info(ctx, "scan begin [where[%s][%+v] cursor[%s][%+v] order[%s] limit[%v] batch[%v]]",
135
                        opt.where, opt.sqlAndArguments, opt.cursorWhere, opt.cursors, opt.order, opt.limit, opt.batch)
136
137
                defer func() { opt.log.Info(ctx, "scan end [count[%v]]", count) }()
138
        }
139
140
        // scan
141
        for hasMore := true; hasMore; hasMore = len(mList) >= opt.batch {
142
                // init model slice
143
                mList = make(TS, 0, opt.batch)
144
145
                // db query
146
                q := tx.Where(opt.cursorWhere, opt.cursors...)
147
                if opt.where != nil {
148
                        q = q.Where(opt.where, opt.sqlAndArguments...)
149
                }
150
                if opt.order != nil {
151
                        q = q.Order(opt.order)
152
                }
153
                if err = q.Limit(opt.batch).Find(&mList).Error; err != nil {
154
                        if opt.log != nil {
155
                                opt.log.Warn(ctx, "scan quit because meet with error [err[%s]]", err)
156
                        }
157
                        break
158
                }
159
160
                if len(mList) > 0 {
161
                        // callback
162
                        if !cb(mList) {
163
                                if opt.log != nil {
164
                                        opt.log.Info(ctx, "scan quit because callback return false")
165
                                }
166
                                break
167
                        }
168
169
                        // get next cursor
170
                        next := mList[len(mList)-1]
171
                        nextVal := reflect.Indirect(reflect.ValueOf(next))
172
                        for idx, col := range opt.cursorColumns {
173
                                fieldVal := nextVal.FieldByNameFunc(func(s string) bool { return strings.EqualFold(s, col) })
174
                                if !fieldVal.IsValid() {
175
                                        fieldVal, _ = utils.GetGormColumnValue(next, col)
176
                                }
177
                                if !fieldVal.IsValid() {
178
                                        err = errors.Errorf("scan cursor column value is not found [col[%s]]", col)
179
                                        if opt.log != nil {
180
                                                opt.log.Error(ctx, "%s", err)
181
                                        }
182
                                        return
183
                                }
184
                                opt.cursors[idx] = fieldVal.Interface()
185
                        }
186
                }
187
188
                // check if exceed max
189
                if count += len(mList); count >= opt.limit {
190
                        if opt.log != nil {
191
                                opt.log.Info(ctx, "scan quit because reach max [count[%v] max[%v]]", count, opt.limit)
192
                        }
193
                        break
194
                }
195
        }
196
197
        return
198
}
func BusinessSoftDeleted.BeforeCreate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

158
func (b *BusinessSoftDeleted) BeforeCreate(tx *gorm.DB) (err error) {
159
        if b == nil {
160
                tx.Statement.SetColumn("uuid", utils.UUID())
161
                tx.Statement.SetColumn("delete_time", nil)
162
                return
163
        }
164
        if b.UUID == [16]byte{0} {
165
                b.UUID = uuid.New()
166
        }
167
        return
168
}
func .convertAnyToTS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

425
func (d *dal[T, TS]) convertAnyToTS(query any) (mList TS, ok bool) {
426
        switch q := query.(type) {
427
        case TS:
428
                ok = true
429
                mList = q
430
        case []*T:
431
                ok = true
432
                mList = TS(q)
433
        case []T:
434
                ok = true
435
                mList = TS(utils.SliceMapping(q, func(t T) *T { return &t }))
436
        case T:
437
                ok = true
438
                mList = TS{&q}
439
        case *T:
440
                ok = true
441
                mList = TS{q}
442
        }
443
        return
444
}
func @206:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

206
func() (err error) {
207
                if tx.Error != nil {
208
                        return
209
                }
210
211
                var bs []byte
212
                switch v := field.(type) {
213
                case string:
214
                        bs = []byte(v)
215
                case *string:
216
                        if v == nil {
217
                                return
218
                        }
219
                        bs = []byte(*v)
220
                case []byte:
221
                        bs = v
222
                case *[]byte:
223
                        if v == nil {
224
                                return
225
                        }
226
                        bs = *v
227
                default:
228
                        return tx.AddError(errors.New("unsupported unmarshal field type"))
229
                }
230
                // be compatible with empty value
231
                if len(bs) == 0 {
232
                        bs = []byte("null")
233
                }
234
235
                return tx.AddError(json.Unmarshal(bs, &obj))
236
        }
func @239:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

239
func() (err error) {
240
                if tx.Error != nil {
241
                        return
242
                }
243
244
                switch v := field.(type) {
245
                case **string, **[]byte, *string, *[]byte:
246
                        if v == nil {
247
                                return
248
                        }
249
                        bs, err := json.Marshal(obj)
250
                        if err != nil {
251
                                return tx.AddError(errors.Wrap(err, "gorm json marshal error"))
252
                        }
253
                        switch f := field.(type) {
254
                        case *string:
255
                                *f = string(bs)
256
                        case **string:
257
                                *f = utils.AnyPtr(string(bs))
258
                        case *[]byte:
259
                                *f = bs
260
                        case **[]byte:
261
                                *f = utils.AnyPtr(bs)
262
                        }
263
                default:
264
                        return tx.AddError(errors.New("unsupported marshal field type"))
265
                }
266
                return
267
        }
func .ShardingByModelList
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

362
func (d *dal[T, TS]) ShardingByModelList(ctx context.Context, src TS) (dst map[string]TS, err error) {
363
        if len(src) == 0 {
364
                return make(map[string]TS), nil
365
        }
366
        writeDB := d.writeDB(ctx)
367
        tableName := d.tableName(writeDB, src[0])
368
        shardingPlugin, ok := writeDB.tableShardingPlugins[tableName]
369
        if !ok {
370
                return map[string]TS{tableName: src}, nil
371
        }
372
        sharded, err := shardingPlugin.ShardingByModelList(ctx, utils.SliceMapping(src, func(t *T) any { return t })...)
373
        if err != nil {
374
                return
375
        }
376
        dst = make(map[string]TS, len(sharded))
377
        for suffix, item := range sharded {
378
                shardingTableName := tableName + suffix
379
                dst[shardingTableName] = TS(utils.SliceMapping(item, func(t any) *T { return t.(*T) }))
380
        }
381
        return
382
}
func .ShardingIDListGen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

345
func (d *dal[T, TS]) ShardingIDListGen(ctx context.Context, amount int) (idList []uint64, err error) {
346
        writeDB := d.writeDB(ctx)
347
        tableName := d.tableName(writeDB, new(T))
348
        tableShardingPlugin, ok := writeDB.tableShardingPlugins[tableName]
349
        if !ok {
350
                return nil, plugins.ErrIDGeneratorNotFound
351
        }
352
        idList = make([]uint64, 0, amount)
353
        for i := 0; i < amount; i++ {
354
                id, err := tableShardingPlugin.ShardingIDGen(ctx)
355
                if err != nil {
356
                        return nil, err
357
                }
358
                idList = append(idList, id)
359
        }
360
        return
361
}
func .QueryInBatches
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

108
func (d *dal[T, TS]) QueryInBatches(ctx context.Context, batchSize int,
109
        fc func(tx *DB, batch int, found TS) error, query any, args ...any) (err error) {
110
        o, args := d.parseOptionFromArgs(args...)
111
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
112
113
        orm := Use(ctx, d.readDBName, AppName(d.appName))
114
        found := make(TS, 0, batchSize)
115
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).FindInBatches(&found, batchSize,
116
                func(tx *gorm.DB, batch int) error {
117
                        wrapper := &DB{
118
                                DB:                   &ormDrv.DB{DB: tx},
119
                                Name:                 orm.Name,
120
                                tableShardingPlugins: orm.tableShardingPlugins,
121
                        }
122
                        return fc(wrapper, batch, found)
123
                },
124
        )
125
        if d.CanIgnore(result.Error) {
126
                return
127
        }
128
        return d.IgnoreErr(result.Error)
129
}
func .Query
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

72
func (d *dal[T, TS]) Query(ctx context.Context, query any, args ...any) (TS, error) {
73
        o, args := d.parseOptionFromArgs(args...)
74
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
75
76
        found := d.ModelSlice()
77
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).Find(&found)
78
        if d.CanIgnore(result.Error) {
79
                return nil, nil
80
        }
81
        return found, d.IgnoreErr(result.Error)
82
}
func .Count
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

131
func (d *dal[T, TS]) Count(ctx context.Context, query any, args ...any) (int64, error) {
132
        var count int64
133
134
        o, args := d.parseOptionFromArgs(args...)
135
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
136
137
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).Count(&count)
138
        if d.CanIgnore(result.Error) {
139
                return 0, nil
140
        }
141
        return count, d.IgnoreErr(result.Error)
142
}
func .QueryLast
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

84
func (d *dal[T, TS]) QueryLast(ctx context.Context, query any, args ...any) (*T, error) {
85
        o, args := d.parseOptionFromArgs(args...)
86
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
87
88
        found := d.Model()
89
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).Last(found)
90
        if d.CanIgnore(result.Error) {
91
                return nil, nil
92
        }
93
        return found, d.IgnoreErr(result.Error)
94
}
func .Transaction
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

261
func (d *dal[T, TS]) Transaction(ctx context.Context, fc func(context.Context) error,
262
        opts ...utils.OptionExtender) error {
263
        orm := GetCtxGormDB(ctx)
264
        o := utils.ApplyOptions[mysqlDALOption](opts...)
265
        if orm == nil || (orm.Name != d.writeDBName && orm.Name != d.readDBName) {
266
                if o.useWriteDB {
267
                        orm = Use(ctx, d.writeDBName, AppName(d.appName))
268
                } else {
269
                        orm = Use(ctx, d.readDBName, AppName(d.appName))
270
                }
271
        }
272
273
        return d.unscopedGormDB(orm.GetProxy().WithContext(ctx), o).Transaction(func(tx *gorm.DB) error {
274
                return fc(SetCtxGormDB(ctx, &DB{
275
                        DB:                   &ormDrv.DB{DB: tx},
276
                        Name:                 orm.Name,
277
                        tableShardingPlugins: orm.tableShardingPlugins,
278
                }))
279
        })
280
}
func .ShardingByValues
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

326
func (d *dal[T, TS]) ShardingByValues(ctx context.Context, src []map[string]any) (
327
        dst map[string][]map[string]any, err error) {
328
        writeDB := d.writeDB(ctx)
329
        tableName := d.tableName(writeDB, new(T))
330
        tableShardingPlugin, ok := writeDB.tableShardingPlugins[tableName]
331
        if !ok {
332
                return map[string][]map[string]any{tableName: src}, nil
333
        }
334
        return tableShardingPlugin.ShardingByValues(ctx, src)
335
}
func Data.Equals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

37
func (d *Data) Equals(o *Data) bool {
38
        if d == nil && o == nil {
39
                return true
40
        }
41
        if d == nil || o == nil {
42
                return false
43
        }
44
        return d.ID == o.ID &&
45
                d.CreateTimeMs == o.CreateTimeMs &&
46
                d.ModifyTimeMs == o.ModifyTimeMs
47
}
func Business.Equals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

137
func (b *Business) Equals(o *Business) bool {
138
        if b == nil && o == nil {
139
                return true
140
        }
141
        if b == nil || o == nil {
142
                return false
143
        }
144
        return b.Data.Equals(&o.Data) &&
145
                b.UUID == o.UUID &&
146
                b.BizCreateTimeMs == o.BizCreateTimeMs &&
147
                b.BizModifyTimeMs == o.BizModifyTimeMs
148
}
func BusinessSoftDeleted.Equals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

191
func (b *BusinessSoftDeleted) Equals(o *BusinessSoftDeleted) bool {
192
        if b == nil && o == nil {
193
                return true
194
        }
195
        if b == nil || o == nil {
196
                return false
197
        }
198
        return b.DataSoftDeleted.Equals(&o.DataSoftDeleted) &&
199
                b.UUID == o.UUID &&
200
                b.BizCreateTimeMs == o.BizCreateTimeMs &&
201
                b.BizModifyTimeMs == o.BizModifyTimeMs
202
}
func DataSoftDeleted.Equals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

83
func (d *DataSoftDeleted) Equals(o *DataSoftDeleted) bool {
84
        if d == nil && o == nil {
85
                return true
86
        }
87
        if d == nil || o == nil {
88
                return false
89
        }
90
        return d.ID == o.ID &&
91
                d.CreateTimeMs == o.CreateTimeMs &&
92
                d.ModifyTimeMs == o.ModifyTimeMs &&
93
                d.DeleteTimeMs == o.DeleteTimeMs &&
94
                d.Deleted == o.Deleted
95
}
func .Take
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

153
func (d *dal[T, TS]) Take(ctx context.Context, dest any, conds ...any) error {
154
        o, args := d.parseOptionFromArgs(conds...)
155
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
156
157
        result := d.ReadDB(ctx).Clauses(o.clauses...).Take(dest, args...)
158
        return d.IgnoreErr(result.Error)
159
}
func .Pluck
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

144
func (d *dal[T, TS]) Pluck(ctx context.Context, column string, dest any,
145
        query any, args ...any) error {
146
        o, args := d.parseOptionFromArgs(args...)
147
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
148
149
        result := d.ReadDB(ctx).Clauses(o.clauses...).Where(query, args...).Pluck(column, dest)
150
        return d.IgnoreErr(result.Error)
151
}
func .Updates
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

229
func (d *dal[T, TS]) Updates(ctx context.Context, columns map[string]any,
230
        query any, args ...any) (int64, error) {
231
        o, args := d.parseOptionFromArgs(args...)
232
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
233
        u := d.WriteDB(ctx).Clauses(o.clauses...).Where(query, args...).Updates(columns)
234
        return u.RowsAffected, u.Error
235
}
func .Update
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

221
func (d *dal[T, TS]) Update(ctx context.Context, column string, value any,
222
        query any, args ...any) (int64, error) {
223
        o, args := d.parseOptionFromArgs(args...)
224
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
225
        u := d.WriteDB(ctx).Clauses(o.clauses...).Where(query, args...).Update(column, value)
226
        return u.RowsAffected, u.Error
227
}
func .FirstOrCreate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

184
func (d *dal[T, TS]) FirstOrCreate(ctx context.Context, mod *T, conds ...any) (int64, error) {
185
        o, conds := d.parseOptionFromArgs(conds...)
186
        ctx = context.WithValue(ctx, fusCtx.KeyDALOption, o)
187
        result := d.WriteDB(ctx).Clauses(o.clauses...).FirstOrCreate(mod, conds...)
188
        return result.RowsAffected, result.Error
189
}
func .SetCtxWriteDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

309
func (d *dal[T, TS]) SetCtxWriteDB(src context.Context) (dst context.Context) {
310
        if orm := GetCtxGormDB(src); orm != nil && orm.Name == d.writeDBName {
311
                return src
312
        }
313
        return SetCtxGormDB(src, Use(src, d.writeDBName, AppName(d.appName)))
314
}
func .SetCtxReadDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

302
func (d *dal[T, TS]) SetCtxReadDB(src context.Context) (dst context.Context) {
303
        if orm := GetCtxGormDB(src); orm != nil && orm.Name == d.readDBName {
304
                return src
305
        }
306
307
        return SetCtxGormDB(src, Use(src, d.readDBName, AppName(d.appName)))
308
}
func DataSoftDeleted.DeleteTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

65
func (d *DataSoftDeleted) DeleteTime() *time.Time {
66
        if !d.DeleteTimeMs.Valid {
67
                return nil
68
        }
69
        return utils.AnyPtr(utils.GetTime(d.DeleteTimeMs.Int64))
70
}
func BusinessSoftDeleted.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

180
func (b *BusinessSoftDeleted) Clone() *BusinessSoftDeleted {
181
        if b == nil {
182
                return nil
183
        }
184
        return &BusinessSoftDeleted{
185
                DataSoftDeleted: *b.DataSoftDeleted.Clone(),
186
                UUID:            b.UUID,
187
                BizCreateTimeMs: b.BizCreateTimeMs,
188
                BizModifyTimeMs: b.BizModifyTimeMs,
189
        }
190
}
func Data.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

27
func (d *Data) Clone() *Data {
28
        if d == nil {
29
                return nil
30
        }
31
        return &Data{
32
                ID:           d.ID,
33
                CreateTimeMs: d.CreateTimeMs,
34
                ModifyTimeMs: d.ModifyTimeMs,
35
        }
36
}
func Business.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

126
func (b *Business) Clone() *Business {
127
        if b == nil {
128
                return nil
129
        }
130
        return &Business{
131
                Data:            *b.Data.Clone(),
132
                UUID:            b.UUID,
133
                BizCreateTimeMs: b.BizCreateTimeMs,
134
                BizModifyTimeMs: b.BizModifyTimeMs,
135
        }
136
}
func @141:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/construct.go:

141
func() *gorm.DB {
142
                                rwlock.RLock()
143
                                defer rwlock.RUnlock()
144
                                return appInstances[opt.AppName][name].GetProxy()
145
                        }
func DataSoftDeleted.Clone
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

71
func (d *DataSoftDeleted) Clone() *DataSoftDeleted {
72
        if d == nil {
73
                return nil
74
        }
75
        return &DataSoftDeleted{
76
                ID:           d.ID,
77
                Deleted:      d.Deleted,
78
                CreateTimeMs: d.CreateTimeMs,
79
                ModifyTimeMs: d.ModifyTimeMs,
80
                DeleteTimeMs: d.DeleteTimeMs,
81
        }
82
}
func @53:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

53
func(o *scanOption) {
54
                o.where = where
55
                o.sqlAndArguments = sqlAndArguments
56
        }
func @116:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

116
func(tx *gorm.DB, batch int) error {
117
                        wrapper := &DB{
118
                                DB:                   &ormDrv.DB{DB: tx},
119
                                Name:                 orm.Name,
120
                                tableShardingPlugins: orm.tableShardingPlugins,
121
                        }
122
                        return fc(wrapper, batch, found)
123
                }
func @33:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/tx.go:

33
func() bool { db = Use(ctx, opt.dbName, AppName(o.appName)); return db != nil }
func @372:82
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

372
func(t *T) any { return t }
func Data.ModifyTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

24
func (d *Data) ModifyTime() time.Time {
25
        return utils.GetTime(d.ModifyTimeMs)
26
}
func DataSoftDeleted.CreateTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

59
func (d *DataSoftDeleted) CreateTime() time.Time {
60
        return utils.GetTime(d.CreateTimeMs)
61
}
func DataSoftDeleted.ModifyTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

62
func (d *DataSoftDeleted) ModifyTime() time.Time {
63
        return utils.GetTime(d.ModifyTimeMs)
64
}
func Data.CreateTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

21
func (d *Data) CreateTime() time.Time {
22
        return utils.GetTime(d.CreateTimeMs)
23
}
func @471:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

471
func(m *mysqlDALOption) {
472
                m.useWriteDB = true
473
        }
func WriteDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

470
func WriteDB() utils.OptionFunc[mysqlDALOption] {
471
        return func(m *mysqlDALOption) {
472
                m.useWriteDB = true
473
        }
474
}
func @465:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

465
func(m *mysqlDALOption) {
466
                m.clauses = append(m.clauses, clauses...)
467
        }
func Business.BeforeCreateFn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

115
func (b *Business) BeforeCreateFn(tx *gorm.DB) func() error {
116
        return func() (err error) {
117
                return b.BeforeCreate(tx)
118
        }
119
}
func @116:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

116
func() (err error) {
117
                return b.BeforeCreate(tx)
118
        }
func Business.BizCreateTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

120
func (b *Business) BizCreateTime() time.Time {
121
        return utils.GetTime(b.BizCreateTimeMs)
122
}
func Business.BizModifyTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

123
func (b *Business) BizModifyTime() time.Time {
124
        return utils.GetTime(b.BizModifyTimeMs)
125
}
func Clauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

464
func Clauses(clauses ...clause.Expression) utils.OptionFunc[mysqlDALOption] {
465
        return func(m *mysqlDALOption) {
466
                m.clauses = append(m.clauses, clauses...)
467
        }
468
}
func @435:36
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

435
func(t T) *T { return &t }
func @379:56
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

379
func(t any) *T { return t.(*T) }
func BusinessSoftDeleted.BeforeCreateFn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

169
func (b *BusinessSoftDeleted) BeforeCreateFn(tx *gorm.DB) func() error {
170
        return func() (err error) {
171
                return b.BeforeCreate(tx)
172
        }
173
}
func @170:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

170
func() (err error) {
171
                return b.BeforeCreate(tx)
172
        }
func .ModelSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

317
func (d *dal[T, TS]) ModelSlice() TS { return make(TS, 0) }
func BusinessSoftDeleted.BizModifyTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

177
func (b *BusinessSoftDeleted) BizModifyTime() time.Time {
178
        return utils.GetTime(b.BizModifyTimeMs)
179
}
func @273:74
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/dal.go:

273
func(tx *gorm.DB) error {
274
                return fc(SetCtxGormDB(ctx, &DB{
275
                        DB:                   &ormDrv.DB{DB: tx},
276
                        Name:                 orm.Name,
277
                        tableShardingPlugins: orm.tableShardingPlugins,
278
                }))
279
        }
func @86:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

86
func(o *scanOption) {
87
                o.log = log
88
        }
func CheckGormErrorFn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

204
func CheckGormErrorFn(tx *gorm.DB) func() error { return func() error { return tx.Error } }
func @204:58
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

204
func() error { return tx.Error }
func JsonUnmarshalFn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

205
func JsonUnmarshalFn(tx *gorm.DB, obj, field any) func() error {
206
        return func() (err error) {
207
                if tx.Error != nil {
208
                        return
209
                }
210
211
                var bs []byte
212
                switch v := field.(type) {
213
                case string:
214
                        bs = []byte(v)
215
                case *string:
216
                        if v == nil {
217
                                return
218
                        }
219
                        bs = []byte(*v)
220
                case []byte:
221
                        bs = v
222
                case *[]byte:
223
                        if v == nil {
224
                                return
225
                        }
226
                        bs = *v
227
                default:
228
                        return tx.AddError(errors.New("unsupported unmarshal field type"))
229
                }
230
                // be compatible with empty value
231
                if len(bs) == 0 {
232
                        bs = []byte("null")
233
                }
234
235
                return tx.AddError(json.Unmarshal(bs, &obj))
236
        }
237
}
func @137:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

137
func() { opt.log.Info(ctx, "scan end [count[%v]]", count) }
func JsonMarshalFn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

238
func JsonMarshalFn(tx *gorm.DB, obj, field any) func() error {
239
        return func() (err error) {
240
                if tx.Error != nil {
241
                        return
242
                }
243
244
                switch v := field.(type) {
245
                case **string, **[]byte, *string, *[]byte:
246
                        if v == nil {
247
                                return
248
                        }
249
                        bs, err := json.Marshal(obj)
250
                        if err != nil {
251
                                return tx.AddError(errors.Wrap(err, "gorm json marshal error"))
252
                        }
253
                        switch f := field.(type) {
254
                        case *string:
255
                                *f = string(bs)
256
                        case **string:
257
                                *f = utils.AnyPtr(string(bs))
258
                        case *[]byte:
259
                                *f = bs
260
                        case **[]byte:
261
                                *f = utils.AnyPtr(bs)
262
                        }
263
                default:
264
                        return tx.AddError(errors.New("unsupported marshal field type"))
265
                }
266
                return
267
        }
268
269
}
func ScanLog
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

85
func ScanLog(log log.Loggable) utils.OptionFunc[scanOption] {
86
        return func(o *scanOption) {
87
                o.log = log
88
        }
89
}
func @80:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

80
func(o *scanOption) {
81
                o.limit = limit
82
        }
func ScanLimit
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

79
func ScanLimit(limit int) utils.OptionFunc[scanOption] {
80
        return func(o *scanOption) {
81
                o.limit = limit
82
        }
83
}
func ScanWhere
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

52
func ScanWhere(where any, sqlAndArguments ...any) utils.OptionFunc[scanOption] {
53
        return func(o *scanOption) {
54
                o.where = where
55
                o.sqlAndArguments = sqlAndArguments
56
        }
57
}
func @47:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

47
func(o *scanOption) {
48
                o.dbName = dbName
49
        }
func ScanUse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/candy.go:

46
func ScanUse(dbName string) utils.OptionFunc[scanOption] {
47
        return func(o *scanOption) {
48
                o.dbName = dbName
49
        }
50
}
func BusinessSoftDeleted.BizCreateTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/model.go:

174
func (b *BusinessSoftDeleted) BizCreateTime() time.Time {
175
        return utils.GetTime(b.BizCreateTimeMs)
176
}
Package Overview: github.com/wfusion/gofusion/db/callbacks 44.0%

Please select a function to see what's left for testing.

SoftDelete(...) github.com/wfusion/gofusion/db/callbacks/soft_delete.go 100.0% 3/3
BuildQuerySQL(...) github.com/wfusion/gofusion/db/callbacks/build_sql.go 100.0% 1/1
BuildUpdateSQL(...) github.com/wfusion/gofusion/db/callbacks/build_sql.go 90.9% 10/11
checkMissingWhereConditions(...) github.com/wfusion/gofusion/db/callbacks/soft_delete.go 88.9% 8/9
BuildDeleteSQL(...) github.com/wfusion/gofusion/db/callbacks/build_sql.go 85.3% 29/34
@43:67(...) github.com/wfusion/gofusion/db/callbacks/soft_delete.go 78.6% 11/14
@15:67(...) github.com/wfusion/gofusion/db/callbacks/soft_delete.go 53.3% 8/15
@29:49(...) github.com/wfusion/gofusion/db/callbacks/auto_incr.go 0.0% 0/47
BuildCreateSQL(...) github.com/wfusion/gofusion/db/callbacks/build_sql.go 0.0% 0/16
CreateAutoIncr(...) github.com/wfusion/gofusion/db/callbacks/auto_incr.go 0.0% 0/8
@53:12(...) github.com/wfusion/gofusion/db/callbacks/auto_incr.go 0.0% 0/1
func SoftDelete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/soft_delete.go:

13
func SoftDelete(db *gorm.DB) {
14
        // update callback
15
        comUtl.MustSuccess(db.Callback().Update().Replace("gorm:update", func(db *gorm.DB) {
16
                if db.Error != nil {
17
                        return
18
                }
19
20
                BuildUpdateSQL(db)
21
                checkMissingWhereConditions(db)
22
23
                if !db.DryRun && db.Error == nil {
24
                        if ok, mode := hasReturning(db, utils.Contains(db.Callback().Update().Clauses, "RETURNING")); ok {
25
                                if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil {
26
                                        dest := db.Statement.Dest
27
                                        db.Statement.Dest = db.Statement.ReflectValue.Addr().Interface()
28
                                        gorm.Scan(rows, db, mode)
29
                                        db.Statement.Dest = dest
30
                                        _ = db.AddError(rows.Close())
31
                                }
32
                        } else {
33
                                result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
34
35
                                if db.AddError(err) == nil {
36
                                        db.RowsAffected, _ = result.RowsAffected()
37
                                }
38
                        }
39
                }
40
        }))
41
42
        // delete callback
43
        comUtl.MustSuccess(db.Callback().Delete().Replace("gorm:delete", func(db *gorm.DB) {
44
                if db.Error != nil {
45
                        return
46
                }
47
48
                BuildDeleteSQL(db)
49
                checkMissingWhereConditions(db)
50
51
                if !db.DryRun && db.Error == nil {
52
                        ok, mode := hasReturning(db, utils.Contains(db.Callback().Delete().Clauses, "RETURNING"))
53
                        if !ok {
54
                                result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
55
                                if db.AddError(err) == nil {
56
                                        db.RowsAffected, _ = result.RowsAffected()
57
                                }
58
59
                                return
60
                        }
61
62
                        if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil {
63
                                gorm.Scan(rows, db, mode)
64
                                _ = db.AddError(rows.Close())
65
                        }
66
                }
67
        }))
68
69
        return
70
}
func BuildQuerySQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/build_sql.go:

15
func BuildQuerySQL(db *gorm.DB) {
16
        callbacks.BuildQuerySQL(db)
17
}
func BuildUpdateSQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/build_sql.go:

48
func BuildUpdateSQL(db *gorm.DB) {
49
        if db.Statement.Schema != nil {
50
                for _, c := range db.Statement.Schema.UpdateClauses {
51
                        db.Statement.AddClause(c)
52
                }
53
        }
54
55
        if db.Statement.SQL.Len() == 0 {
56
                db.Statement.SQL.Grow(180)
57
                db.Statement.AddClauseIfNotExists(clause.Update{})
58
                if _, ok := db.Statement.Clauses["SET"]; !ok {
59
                        if set := callbacks.ConvertToAssignments(db.Statement); len(set) != 0 {
60
                                db.Statement.AddClause(set)
61
                        } else {
62
                                return
63
                        }
64
                }
65
66
                db.Statement.Build(db.Statement.BuildClauses...)
67
        }
68
}
func checkMissingWhereConditions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/soft_delete.go:

72
func checkMissingWhereConditions(db *gorm.DB) {
73
        if !db.AllowGlobalUpdate && db.Error == nil {
74
                where, withCondition := db.Statement.Clauses["WHERE"]
75
                if withCondition {
76
                        if softdelete.IsClausesWithSoftDelete(db.Statement.Clauses) {
77
                                whereClause, _ := where.Expression.(clause.Where)
78
                                withCondition = len(whereClause.Exprs) > 1
79
                        }
80
                }
81
                if !withCondition {
82
                        _ = db.AddError(gorm.ErrMissingWhereClause)
83
                }
84
                return
85
        }
86
}
func BuildDeleteSQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/build_sql.go:

70
func BuildDeleteSQL(db *gorm.DB) {
71
        if db.Statement.Schema != nil {
72
                for _, c := range db.Statement.Schema.DeleteClauses {
73
                        db.Statement.AddClause(c)
74
                }
75
        }
76
77
        if db.Statement.SQL.Len() > 0 {
78
                return
79
        }
80
81
        stmt := db.Statement
82
        stmt.SQL.Grow(180)
83
        if softdelete.IsClausesWithSoftDelete(db.Statement.Clauses) {
84
                stmt.AddClauseIfNotExists(clause.Update{})
85
86
                if stmt.Schema != nil {
87
                        _, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields)
88
                        column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
89
90
                        if len(values) > 0 {
91
                                stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
92
                        }
93
94
                        if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
95
                                _, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
96
                                column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
97
98
                                if len(values) > 0 {
99
                                        stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
100
                                }
101
                        }
102
                }
103
104
                stmt.AddClauseIfNotExists(clause.From{})
105
                stmt.Build(stmt.DB.Callback().Update().Clauses...)
106
        } else {
107
                stmt.AddClauseIfNotExists(clause.Delete{})
108
109
                if stmt.Schema != nil {
110
                        _, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields)
111
                        column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
112
113
                        if len(values) > 0 {
114
                                stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
115
                        }
116
117
                        if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
118
                                _, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
119
                                column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
120
121
                                if len(values) > 0 {
122
                                        stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
123
                                }
124
                        }
125
                }
126
127
                stmt.AddClauseIfNotExists(clause.From{})
128
                stmt.Build(stmt.BuildClauses...)
129
        }
130
}
func @43:67
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/soft_delete.go:

43
func(db *gorm.DB) {
44
                if db.Error != nil {
45
                        return
46
                }
47
48
                BuildDeleteSQL(db)
49
                checkMissingWhereConditions(db)
50
51
                if !db.DryRun && db.Error == nil {
52
                        ok, mode := hasReturning(db, utils.Contains(db.Callback().Delete().Clauses, "RETURNING"))
53
                        if !ok {
54
                                result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
55
                                if db.AddError(err) == nil {
56
                                        db.RowsAffected, _ = result.RowsAffected()
57
                                }
58
59
                                return
60
                        }
61
62
                        if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil {
63
                                gorm.Scan(rows, db, mode)
64
                                _ = db.AddError(rows.Close())
65
                        }
66
                }
67
        }
func @15:67
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/soft_delete.go:

15
func(db *gorm.DB) {
16
                if db.Error != nil {
17
                        return
18
                }
19
20
                BuildUpdateSQL(db)
21
                checkMissingWhereConditions(db)
22
23
                if !db.DryRun && db.Error == nil {
24
                        if ok, mode := hasReturning(db, utils.Contains(db.Callback().Update().Clauses, "RETURNING")); ok {
25
                                if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil {
26
                                        dest := db.Statement.Dest
27
                                        db.Statement.Dest = db.Statement.ReflectValue.Addr().Interface()
28
                                        gorm.Scan(rows, db, mode)
29
                                        db.Statement.Dest = dest
30
                                        _ = db.AddError(rows.Close())
31
                                }
32
                        } else {
33
                                result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
34
35
                                if db.AddError(err) == nil {
36
                                        db.RowsAffected, _ = result.RowsAffected()
37
                                }
38
                        }
39
                }
40
        }
func @29:49
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/auto_incr.go:

29
func(db *gorm.DB) {
30
                        if db.Error != nil {
31
                                return
32
                        }
33
34
                        BuildCreateSQL(db)
35
36
                        isDryRun := !db.DryRun && db.Error == nil
37
                        if !isDryRun {
38
                                return
39
                        }
40
41
                        ok, mode := hasReturning(db, utils.Contains(db.Callback().Create().Clauses, "RETURNING"))
42
                        if ok {
43
                                if c, ok := db.Statement.Clauses["ON CONFLICT"]; ok {
44
                                        if onConflict, _ := c.Expression.(clause.OnConflict); onConflict.DoNothing {
45
                                                mode |= gorm.ScanOnConflictDoNothing
46
                                        }
47
                                }
48
49
                                rows, err := db.Statement.ConnPool.QueryContext(
50
                                        db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
51
                                )
52
                                if db.AddError(err) == nil {
53
                                        defer func() { _ = db.AddError(rows.Close()) }()
54
                                        gorm.Scan(rows, db, mode)
55
                                }
56
57
                                return
58
                        }
59
60
                        result, err := db.Statement.ConnPool.ExecContext(
61
                                db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
62
                        )
63
                        if err != nil {
64
                                _ = db.AddError(err)
65
                                return
66
                        }
67
68
                        db.RowsAffected, _ = result.RowsAffected()
69
                        if db.RowsAffected != 0 && db.Statement.Schema != nil &&
70
                                db.Statement.Schema.PrioritizedPrimaryField != nil &&
71
                                db.Statement.Schema.PrioritizedPrimaryField.HasDefaultValue {
72
                                insertID, err := result.LastInsertId()
73
                                insertOk := err == nil && insertID > 0
74
                                if !insertOk {
75
                                        _ = db.AddError(err)
76
                                        return
77
                                }
78
79
                                switch db.Statement.ReflectValue.Kind() {
80
                                case reflect.Slice, reflect.Array:
81
                                        if lastInsertIDReversed {
82
                                                for i := db.Statement.ReflectValue.Len() - 1; i >= 0; i-- {
83
                                                        rv := db.Statement.ReflectValue.Index(i)
84
                                                        if reflect.Indirect(rv).Kind() != reflect.Struct {
85
                                                                break
86
                                                        }
87
88
                                                        _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
89
                                                        if isZero {
90
                                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID))
91
                                                                //insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
92
                                                                insertID -= autoIncrIncr
93
                                                        }
94
                                                }
95
                                        } else {
96
                                                for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
97
                                                        rv := db.Statement.ReflectValue.Index(i)
98
                                                        if reflect.Indirect(rv).Kind() != reflect.Struct {
99
                                                                break
100
                                                        }
101
102
                                                        if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv); isZero {
103
                                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID))
104
                                                                //insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
105
                                                                insertID += autoIncrIncr
106
                                                        }
107
                                                }
108
                                        }
109
                                case reflect.Struct:
110
                                        _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
111
                                        if isZero {
112
                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, db.Statement.ReflectValue, insertID))
113
                                        }
114
                                }
115
                        }
116
                }
func BuildCreateSQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/build_sql.go:

19
func BuildCreateSQL(db *gorm.DB) {
20
        supportReturning := utils.Contains(db.Callback().Create().Clauses, "RETURNING")
21
        if db.Statement.Schema != nil {
22
                if !db.Statement.Unscoped {
23
                        for _, c := range db.Statement.Schema.CreateClauses {
24
                                db.Statement.AddClause(c)
25
                        }
26
                }
27
28
                if supportReturning && len(db.Statement.Schema.FieldsWithDefaultDBValue) > 0 {
29
                        if _, ok := db.Statement.Clauses["RETURNING"]; !ok {
30
                                fromColumns := make([]clause.Column, 0, len(db.Statement.Schema.FieldsWithDefaultDBValue))
31
                                for _, field := range db.Statement.Schema.FieldsWithDefaultDBValue {
32
                                        fromColumns = append(fromColumns, clause.Column{Name: field.DBName})
33
                                }
34
                                db.Statement.AddClause(clause.Returning{Columns: fromColumns})
35
                        }
36
                }
37
        }
38
39
        if db.Statement.SQL.Len() == 0 {
40
                db.Statement.SQL.Grow(180)
41
                db.Statement.AddClauseIfNotExists(clause.Insert{})
42
                db.Statement.AddClause(callbacks.ConvertToCreateValues(db.Statement))
43
44
                db.Statement.Build(db.Statement.BuildClauses...)
45
        }
46
}
func CreateAutoIncr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/auto_incr.go:

16
func CreateAutoIncr(db *gorm.DB, gormDialector gorm.Dialector, autoIncrIncr int64) {
17
        withReturning := false
18
        dialector := gormDialector.(*Dialector)
19
        if !dialector.Config.SkipInitializeWithVersion && strings.Contains(dialector.ServerVersion, "MariaDB") {
20
                withReturning = checkVersion(dialector.ServerVersion, "10.5")
21
        }
22
23
        lastInsertIDReversed := false
24
        if !dialector.Config.DisableWithReturning && withReturning {
25
                lastInsertIDReversed = true
26
        }
27
28
        comUtl.MustSuccess(
29
                db.Callback().Create().Replace("gorm:create", func(db *gorm.DB) {
30
                        if db.Error != nil {
31
                                return
32
                        }
33
34
                        BuildCreateSQL(db)
35
36
                        isDryRun := !db.DryRun && db.Error == nil
37
                        if !isDryRun {
38
                                return
39
                        }
40
41
                        ok, mode := hasReturning(db, utils.Contains(db.Callback().Create().Clauses, "RETURNING"))
42
                        if ok {
43
                                if c, ok := db.Statement.Clauses["ON CONFLICT"]; ok {
44
                                        if onConflict, _ := c.Expression.(clause.OnConflict); onConflict.DoNothing {
45
                                                mode |= gorm.ScanOnConflictDoNothing
46
                                        }
47
                                }
48
49
                                rows, err := db.Statement.ConnPool.QueryContext(
50
                                        db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
51
                                )
52
                                if db.AddError(err) == nil {
53
                                        defer func() { _ = db.AddError(rows.Close()) }()
54
                                        gorm.Scan(rows, db, mode)
55
                                }
56
57
                                return
58
                        }
59
60
                        result, err := db.Statement.ConnPool.ExecContext(
61
                                db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...,
62
                        )
63
                        if err != nil {
64
                                _ = db.AddError(err)
65
                                return
66
                        }
67
68
                        db.RowsAffected, _ = result.RowsAffected()
69
                        if db.RowsAffected != 0 && db.Statement.Schema != nil &&
70
                                db.Statement.Schema.PrioritizedPrimaryField != nil &&
71
                                db.Statement.Schema.PrioritizedPrimaryField.HasDefaultValue {
72
                                insertID, err := result.LastInsertId()
73
                                insertOk := err == nil && insertID > 0
74
                                if !insertOk {
75
                                        _ = db.AddError(err)
76
                                        return
77
                                }
78
79
                                switch db.Statement.ReflectValue.Kind() {
80
                                case reflect.Slice, reflect.Array:
81
                                        if lastInsertIDReversed {
82
                                                for i := db.Statement.ReflectValue.Len() - 1; i >= 0; i-- {
83
                                                        rv := db.Statement.ReflectValue.Index(i)
84
                                                        if reflect.Indirect(rv).Kind() != reflect.Struct {
85
                                                                break
86
                                                        }
87
88
                                                        _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
89
                                                        if isZero {
90
                                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID))
91
                                                                //insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
92
                                                                insertID -= autoIncrIncr
93
                                                        }
94
                                                }
95
                                        } else {
96
                                                for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
97
                                                        rv := db.Statement.ReflectValue.Index(i)
98
                                                        if reflect.Indirect(rv).Kind() != reflect.Struct {
99
                                                                break
100
                                                        }
101
102
                                                        if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv); isZero {
103
                                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID))
104
                                                                //insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
105
                                                                insertID += autoIncrIncr
106
                                                        }
107
                                                }
108
                                        }
109
                                case reflect.Struct:
110
                                        _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
111
                                        if isZero {
112
                                                _ = db.AddError(db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, db.Statement.ReflectValue, insertID))
113
                                        }
114
                                }
115
                        }
116
                }),
117
        )
118
}
func @53:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/callbacks/auto_incr.go:

53
func() { _ = db.AddError(rows.Close()) }
Package Overview: github.com/wfusion/gofusion/db/plugins 61.0%

Please select a function to see what's left for testing.

tableSharding.replaceStatementClauseAndSchema(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 8/8
@697:23(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 8/8
tableSharding.registerCallbacks(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 6/6
tableSharding.replaceOrderByTableName(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 6/6
tableSharding.Initialize(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 5/5
@718:23(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 5/5
newShardingDialector(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 4/4
shardingDialector.Migrator(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 4/4
@252:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 3/3
@274:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 3/3
@1102:5(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@240:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@1077:28(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
tableSharding.replaceCondition(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@251:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@1011:9(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@262:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@273:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 2/2
@294:9(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.updateCallback(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.rawCallback(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.queryCallback(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
@917:42(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableShardingIsInsert(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.isIgnored(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.createCallback(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
@332:37(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.replaceConstraint(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
@151:33(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.Name(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.deleteCallback(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
@1006:9(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 1/1
tableSharding.checkDiffSuffixesByModel(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 90.5% 19/21
@804:23(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 88.2% 15/17
tableSharding.suffixes(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 87.5% 7/8
@1049:10(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 87.5% 7/8
@1063:10(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 87.5% 7/8
tableSharding.ShardingByModelList(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 83.3% 15/18
@646:12(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 83.3% 5/6
shardingMigrator.AutoMigrate(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 81.2% 13/16
shardingMigrator.DropTable(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 81.2% 13/16
@371:15(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 80.0% 8/10
DefaultTableSharding(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 77.8% 14/18
@854:23(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 77.8% 7/9
tableSharding.setPrimaryKeyByModel(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 76.9% 10/13
@438:31(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 76.6% 36/47
tableSharding.dispatchTableByModel(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.6% 31/41
shardingMigrator.getShardingDst(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.0% 9/12
tableSharding.getModelReflectValue(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.0% 6/8
shardingMigrator.tableName(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.0% 6/8
tableSharding.wrapDispatchTableBySQL(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.0% 3/4
tableSharding.ignore(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 75.0% 3/4
tableSharding.nonInsertValue(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 71.4% 5/7
tableSharding.defaultShardingFunc(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 68.0% 17/25
tableSharding.ShardingIDGen(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 66.7% 2/3
@1093:5(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 60.0% 3/5
@1106:10(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 58.6% 17/29
tableSharding.createTableIfNotExists(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 54.5% 12/22
@1080:5(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 37.5% 3/8
tableSharding.dispatchTableBySQL(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 34.7% 26/75
@580:20(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 20.0% 6/30
tableSharding.insertValue(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/35
tableSharding.ShardingByValues(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/15
@655:11(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/12
@581:22(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/8
@241:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/3
@263:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/3
shardingDialector.SavePoint(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/3
shardingDialector.RollbackTo(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/3
@674:15(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/3
@284:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/2
@285:3(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 0.0% 0/2
@1003:10(...) github.com/wfusion/gofusion/db/plugins/table_sharding.go 100.0% 0/0
func tableSharding.replaceStatementClauseAndSchema
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

579
func (t *tableSharding) replaceStatementClauseAndSchema(db *gorm.DB, opt *tableShardingDispatchOption) {
580
        changeExprFunc := func(src []clause.Expression) (dst []clause.Expression) {
581
                changeTableFunc := func(src any) (dst any, ok bool) {
582
                        switch col := src.(type) {
583
                        case clause.Column:
584
                                if col.Table == t.config.Table {
585
                                        col.Table = db.Statement.Table
586
                                        return col, true
587
                                }
588
                        case clause.Table:
589
                                if col.Name == t.config.Table {
590
                                        col.Name = db.Statement.Table
591
                                        return col, true
592
                                }
593
                        }
594
                        return
595
                }
596
                dst = make([]clause.Expression, 0, len(src))
597
                for _, srcExpr := range src {
598
                        switch expr := srcExpr.(type) {
599
                        case clause.IN:
600
                                if col, ok := changeTableFunc(expr.Column); ok {
601
                                        expr.Column = col
602
                                }
603
                                dst = append(dst, expr)
604
                        case clause.Eq:
605
                                if col, ok := changeTableFunc(expr.Column); ok {
606
                                        expr.Column = col
607
                                }
608
                                dst = append(dst, expr)
609
                        case clause.Neq:
610
                                if col, ok := changeTableFunc(expr.Column); ok {
611
                                        expr.Column = col
612
                                }
613
                                dst = append(dst, expr)
614
                        case clause.Gt:
615
                                if col, ok := changeTableFunc(expr.Column); ok {
616
                                        expr.Column = col
617
                                }
618
                                dst = append(dst, expr)
619
                        case clause.Gte:
620
                                if col, ok := changeTableFunc(expr.Column); ok {
621
                                        expr.Column = col
622
                                }
623
                                dst = append(dst, expr)
624
                        case clause.Lt:
625
                                if col, ok := changeTableFunc(expr.Column); ok {
626
                                        expr.Column = col
627
                                }
628
                                dst = append(dst, expr)
629
                        case clause.Lte:
630
                                if col, ok := changeTableFunc(expr.Column); ok {
631
                                        expr.Column = col
632
                                }
633
                                dst = append(dst, expr)
634
                        case clause.Like:
635
                                if col, ok := changeTableFunc(expr.Column); ok {
636
                                        expr.Column = col
637
                                }
638
                                dst = append(dst, expr)
639
                        default:
640
                                dst = append(dst, expr)
641
                        }
642
                }
643
                return
644
        }
645
        changeClausesMapping := map[string]func(cls clause.Clause){
646
                "WHERE": func(cls clause.Clause) {
647
                        whereClause, ok := cls.Expression.(clause.Where)
648
                        if !ok {
649
                                return
650
                        }
651
                        whereClause.Exprs = changeExprFunc(whereClause.Exprs)
652
                        cls.Expression = whereClause
653
                        db.Statement.Clauses["WHERE"] = cls
654
                },
655
                "FROM": func(cls clause.Clause) {
656
                        fromClause, ok := cls.Expression.(clause.From)
657
                        if !ok {
658
                                return
659
                        }
660
                        tables := make([]clause.Table, 0, len(fromClause.Tables))
661
                        for _, table := range fromClause.Tables {
662
                                if table.Name == t.config.Table {
663
                                        table.Name = db.Statement.Table
664
                                        tables = append(tables, table)
665
                                } else {
666
                                        tables = append(tables, table)
667
                                }
668
                        }
669
                        fromClause.Tables = tables
670
                        cls.Expression = fromClause
671
                        db.Statement.Clauses["FROM"] = cls
672
                },
673
                // TODO: check if order by contains table name
674
                "ORDER BY": func(cls clause.Clause) {
675
                        _, ok := cls.Expression.(clause.OrderBy)
676
                        if !ok {
677
                                return
678
                        }
679
                },
680
        }
681
682
        for name, cls := range db.Statement.Clauses {
683
                if mappingFunc, ok := changeClausesMapping[name]; ok {
684
                        mappingFunc(cls)
685
                }
686
        }
687
688
        if opt.isInsert {
689
                db.Clauses(clause.Insert{Table: clause.Table{Name: db.Statement.Table}})
690
        } else {
691
                db.Clauses(clause.From{Tables: []clause.Table{{Name: db.Statement.Table}}})
692
        }
693
}
func @697:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

697
func(node sqlparser.Node) (err error) {
698
                        n, ok := node.(*sqlparser.BinaryExpr)
699
                        if !ok {
700
                                return
701
                        }
702
703
                        x, ok := n.X.(*sqlparser.QualifiedRef)
704
                        if !ok || x.Table == nil || x.Table.Name != oldTableName {
705
                                return
706
                        }
707
708
                        x.Table.Name = newTableName
709
                        return
710
                }
func tableSharding.registerCallbacks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

203
func (t *tableSharding) registerCallbacks(db *gorm.DB) {
204
        utils.MustSuccess(db.Callback().
205
                Create().
206
                After("gorm:before_create").
207
                Before("gorm:save_before_associations").
208
                Register(t.Name(), t.createCallback))
209
210
        utils.MustSuccess(db.Callback().
211
                Query().
212
                Before("gorm:query").
213
                Register(t.Name(), t.queryCallback))
214
215
        utils.MustSuccess(db.Callback().
216
                Update().
217
                After("gorm:before_update").
218
                Before("gorm:save_before_associations").
219
                Register(t.Name(), t.updateCallback))
220
221
        utils.MustSuccess(db.Callback().
222
                Delete().
223
                After("gorm:before_delete").
224
                Before("gorm:delete_before_associations").
225
                Register(t.Name(), t.deleteCallback))
226
227
        utils.MustSuccess(db.Callback().
228
                Row().
229
                Before("gorm:row").
230
                Register(t.Name(), t.queryCallback))
231
232
        utils.MustSuccess(db.Callback().
233
                Raw().
234
                Before("gorm:raw").
235
                Register(t.Name(), t.rawCallback))
236
}
func tableSharding.replaceOrderByTableName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

938
func (t *tableSharding) replaceOrderByTableName(
939
        orderBy []*sqlparser.OrderingTerm, oldName, newName string) []*sqlparser.OrderingTerm {
940
        for i, term := range orderBy {
941
                if x, ok := term.X.(*sqlparser.QualifiedRef); ok {
942
                        if x.Table.Name == oldName {
943
                                x.Table.Name = newName
944
                                orderBy[i].X = x
945
                        }
946
                }
947
        }
948
        return orderBy
949
}
func tableSharding.Initialize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

136
func (t *tableSharding) Initialize(db *gorm.DB) (err error) {
137
        db.Dialector = newShardingDialector(db.Dialector, t)
138
139
        t.DB = db
140
        t.shardingFunc = t.defaultShardingFunc()
141
        t.registerCallbacks(db)
142
        return
143
}
func @718:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

718
func(node sqlparser.Node) (err error) {
719
                        n, ok := node.(*sqlparser.QualifiedRef)
720
                        if !ok || n.Table == nil || n.Table.Name != oldTableName {
721
                                return
722
                        }
723
724
                        n.Table.Name = newTableName
725
                        return
726
                }
func newShardingDialector
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1163
func newShardingDialector(d gorm.Dialector, s *tableSharding) shardingDialector {
1164
        if sd, ok := d.(shardingDialector); ok {
1165
                sd.shardingMap[s.config.Table] = s
1166
                return sd
1167
        }
1168
1169
        return shardingDialector{
1170
                Dialector:   d,
1171
                shardingMap: map[string]*tableSharding{s.config.Table: s},
1172
        }
1173
}
func shardingDialector.Migrator
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1175
func (s shardingDialector) Migrator(db *gorm.DB) gorm.Migrator {
1176
        m := s.Dialector.Migrator(db)
1177
        if (*tableSharding)(nil).isIgnored(db)() {
1178
                return m
1179
        }
1180
        return &shardingMigrator{
1181
                Migrator:    m,
1182
                db:          db,
1183
                shardingMap: s.shardingMap,
1184
                dialector:   s.Dialector,
1185
        }
1186
}
func @252:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

252
func() bool {
253
                        callbacks.BuildQuerySQL(db)
254
                        t.wrapDispatchTableBySQL(db)
255
                        return true
256
                }
func @274:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

274
func() bool {
275
                        callbacks.BuildDeleteSQL(db)
276
                        t.wrapDispatchTableBySQL(db)
277
                        return true
278
                }
func @1102:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1102
func() bool { data = []byte(v); return true }
func @240:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

240
func() bool { ok1, ok2 := t.dispatchTableByModel(db, tableShardingIsInsert()); return ok1 || ok2 }
func @1077:28
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1077
func(v string) (data []byte) {
1078
                        utils.IfAny(
1079
                                // number
1080
                                func() (ok bool) {
1081
                                        num := new(big.Float)
1082
                                        if _, ok = num.SetString(v); !ok {
1083
                                                return
1084
                                        }
1085
                                        gobEncoded, err := num.GobEncode()
1086
                                        if err != nil {
1087
                                                return false
1088
                                        }
1089
                                        data = gobEncoded
1090
                                        return
1091
                                },
1092
                                // uuid
1093
                                func() bool {
1094
                                        uid, err := uuid.Parse(v)
1095
                                        if err != nil {
1096
                                                return false
1097
                                        }
1098
                                        data = uid[:]
1099
                                        return true
1100
                                },
1101
                                // bytes
1102
                                func() bool { data = []byte(v); return true },
1103
                        )
1104
                        return
1105
                }
func tableSharding.replaceCondition
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

695
func (t *tableSharding) replaceCondition(conditions sqlparser.Expr, oldTableName, newTableName string) (err error) {
696
        err = sqlparser.Walk(
697
                sqlparser.VisitFunc(func(node sqlparser.Node) (err error) {
698
                        n, ok := node.(*sqlparser.BinaryExpr)
699
                        if !ok {
700
                                return
701
                        }
702
703
                        x, ok := n.X.(*sqlparser.QualifiedRef)
704
                        if !ok || x.Table == nil || x.Table.Name != oldTableName {
705
                                return
706
                        }
707
708
                        x.Table.Name = newTableName
709
                        return
710
                }),
711
                conditions,
712
        )
713
        return
714
}
func @251:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

251
func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 }
func @1011:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1011
func() bool {
1012
                _, ok := db.Statement.Settings.Load(shardingIgnoreStoreKey)
1013
                return ok
1014
        }
func @262:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

262
func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 }
func @273:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

273
func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 }
func @294:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

294
func(t *tableShardingDispatchOption) {
295
                t.isInsert = true
296
        }
func tableSharding.updateCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

259
func (t *tableSharding) updateCallback(db *gorm.DB) {
260
        utils.IfAny(
261
                t.isIgnored(db),
262
                func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 },
263
                func() bool {
264
                        callbacks.BuildUpdateSQL(db)
265
                        t.wrapDispatchTableBySQL(db)
266
                        return true
267
                },
268
        )
269
}
func tableSharding.rawCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

281
func (t *tableSharding) rawCallback(db *gorm.DB) {
282
        utils.IfAny(
283
                t.isIgnored(db),
284
                func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 },
285
                func() bool { t.wrapDispatchTableBySQL(db); return true },
286
        )
287
}
func tableSharding.queryCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

248
func (t *tableSharding) queryCallback(db *gorm.DB) {
249
        utils.IfAny(
250
                t.isIgnored(db),
251
                func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 },
252
                func() bool {
253
                        callbacks.BuildQuerySQL(db)
254
                        t.wrapDispatchTableBySQL(db)
255
                        return true
256
                },
257
        )
258
}
func @917:42
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

917
func(v string) bool { return strings.EqualFold(v, key) }
func tableShardingIsInsert
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

293
func tableShardingIsInsert() utils.OptionFunc[tableShardingDispatchOption] {
294
        return func(t *tableShardingDispatchOption) {
295
                t.isInsert = true
296
        }
297
}
func tableSharding.isIgnored
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1010
func (t *tableSharding) isIgnored(db *gorm.DB) func() bool {
1011
        return func() bool {
1012
                _, ok := db.Statement.Settings.Load(shardingIgnoreStoreKey)
1013
                return ok
1014
        }
1015
}
func tableSharding.createCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

237
func (t *tableSharding) createCallback(db *gorm.DB) {
238
        utils.IfAny(
239
                t.isIgnored(db),
240
                func() bool { ok1, ok2 := t.dispatchTableByModel(db, tableShardingIsInsert()); return ok1 || ok2 },
241
                func() bool {
242
                        callbacks.BuildCreateSQL(db)
243
                        t.wrapDispatchTableBySQL(db, tableShardingIsInsert())
244
                        return true
245
                },
246
        )
247
}
func @332:37
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

332
func(v string) bool { return strings.EqualFold(v, key) }
func tableSharding.replaceConstraint
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

716
func (t *tableSharding) replaceConstraint(constraints sqlparser.Node, oldTableName, newTableName string) (err error) {
717
        return sqlparser.Walk(
718
                sqlparser.VisitFunc(func(node sqlparser.Node) (err error) {
719
                        n, ok := node.(*sqlparser.QualifiedRef)
720
                        if !ok || n.Table == nil || n.Table.Name != oldTableName {
721
                                return
722
                        }
723
724
                        n.Table.Name = newTableName
725
                        return
726
                }),
727
                constraints,
728
        )
729
}
func @151:33
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

151
func(v string) bool { return strings.EqualFold(v, key) }
func tableSharding.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

132
func (t *tableSharding) Name() string {
133
        return fmt.Sprintf("gorm:sharding:%s:%s", t.config.Database, t.config.Table)
134
}
func tableSharding.deleteCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

270
func (t *tableSharding) deleteCallback(db *gorm.DB) {
271
        utils.IfAny(
272
                t.isIgnored(db),
273
                func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 },
274
                func() bool {
275
                        callbacks.BuildDeleteSQL(db)
276
                        t.wrapDispatchTableBySQL(db)
277
                        return true
278
                },
279
        )
280
}
func @1006:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1006
func() {
1007
                db.Statement.Settings.Delete(shardingIgnoreStoreKey)
1008
        }
func tableSharding.checkDiffSuffixesByModel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

906
func (t *tableSharding) checkDiffSuffixesByModel(db *gorm.DB) (err error) {
907
        reflectVal := utils.IndirectValue(db.Statement.ReflectValue)
908
        if reflectVal.Kind() != reflect.Array && reflectVal.Kind() != reflect.Slice {
909
                return
910
        }
911
912
        suffix := ""
913
        for i := 0; i < reflectVal.Len(); i++ {
914
                reflectItemVal := reflect.Indirect(reflectVal.Index(i))
915
                values := make([]any, 0, len(t.config.ShardingKeys))
916
                for _, key := range t.config.ShardingKeys {
917
                        val := reflectItemVal.FieldByNameFunc(func(v string) bool { return strings.EqualFold(v, key) })
918
                        if !val.IsValid() {
919
                                val, _ = utils.GetGormColumnValue(reflectItemVal, key)
920
                        }
921
                        if !val.IsValid() {
922
                                return db.AddError(ErrMissingShardingKey)
923
                        }
924
                        values = append(values, val.Interface())
925
                }
926
                subSuffix, err := t.shardingFunc(db.Statement.Context, values...)
927
                if err != nil {
928
                        return db.AddError(err)
929
                }
930
                if suffix != "" && suffix != subSuffix {
931
                        return db.AddError(ErrDiffSuffixDML)
932
                }
933
                suffix = subSuffix
934
        }
935
        return
936
}
func @804:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

804
func(node sqlparser.Node) (err error) {
805
                        n, ok := node.(*sqlparser.BinaryExpr)
806
                        if !ok {
807
                                return
808
                        }
809
                        if n.Op != sqlparser.EQ {
810
                                return
811
                        }
812
813
                        switch x := n.X.(type) {
814
                        case *sqlparser.Ident:
815
                                if x.Name != key {
816
                                        return
817
                                }
818
                        case *sqlparser.QualifiedRef:
819
                                if !ok || x.Table.Name != tableName || x.Column.Name != key {
820
                                        return
821
                                }
822
                        }
823
824
                        found = true
825
                        switch expr := n.Y.(type) {
826
                        case *sqlparser.BindExpr:
827
                                value = args[expr.Pos]
828
                        case *sqlparser.StringLit:
829
                                value = expr.Value
830
                        case *sqlparser.NumberLit:
831
                                value = expr.Value
832
                        default:
833
                                return sqlparser.ErrNotImplemented
834
                        }
835
836
                        return
837
                }
func tableSharding.suffixes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

983
func (t *tableSharding) suffixes() (suffixes []string, err error) {
984
        switch {
985
        case t.config.ShardingKeyByRawValue:
986
                if len(t.config.ShardingKeysForMigrating) == 0 {
987
                        return nil, errors.New("sharding key by raw value but do not configure keys for migrating")
988
                }
989
990
                for _, shardingKey := range t.config.ShardingKeysForMigrating {
991
                        suffixes = append(suffixes, fmt.Sprintf(t.suffixFormat, shardingKey))
992
                }
993
        default:
994
                for i := 0; i < int(t.config.NumberOfShards); i++ {
995
                        suffixes = append(suffixes, fmt.Sprintf(t.suffixFormat, i))
996
                }
997
        }
998
        return
999
}
func @1049:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1049
func(ctx context.Context, values ...any) (suffix string, err error) {
1050
                        data := make([]string, 0, len(values))
1051
                        for _, value := range values {
1052
                                v, err := cast.ToStringE(value)
1053
                                if err != nil {
1054
                                        return "", err
1055
                                }
1056
                                data = append(data, v)
1057
                        }
1058
                        shardingKey := strings.Join(data, constant.Underline)
1059
                        return fmt.Sprintf("_%s", shardingKey), nil
1060
                }
func @1063:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1063
func(ctx context.Context, values ...any) (suffix string, err error) {
1064
                        params := make(map[string]any, len(t.config.ShardingKeys))
1065
                        for idx, column := range t.config.ShardingKeys {
1066
                                params[column] = values[idx]
1067
                        }
1068
1069
                        result, err := t.config.ShardingKeyExpr(ctx, params)
1070
                        if err != nil {
1071
                                return
1072
                        }
1073
                        shardingKey := int64(math.Mod(cast.ToFloat64(result), numberOfShardsFloat64))
1074
                        return fmt.Sprintf(t.suffixFormat, shardingKey), nil
1075
                }
func tableSharding.ShardingByModelList
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

145
func (t *tableSharding) ShardingByModelList(ctx context.Context, src ...any) (dst map[string][]any, err error) {
146
        dst = make(map[string][]any, len(t.config.ShardingKeys))
147
        for _, m := range src {
148
                val := reflect.Indirect(reflect.ValueOf(m))
149
                shardingValues := make([]any, 0, len(t.config.ShardingKeys))
150
                for _, key := range t.config.ShardingKeys {
151
                        field := val.FieldByNameFunc(func(v string) bool { return strings.EqualFold(v, key) })
152
                        if !field.IsValid() {
153
                                field, _ = utils.GetGormColumnValue(val, key)
154
                        }
155
                        if !field.IsValid() {
156
                                return dst, ErrMissingShardingKey
157
                        }
158
                        if key == t.shardingPrimaryKey && field.IsZero() {
159
                                return dst, ErrInvalidID
160
                        }
161
                        shardingValues = append(shardingValues, field.Interface())
162
                }
163
                suffix, err := t.shardingFunc(ctx, shardingValues...)
164
                if err != nil {
165
                        return dst, err
166
                }
167
                dst[suffix] = append(dst[suffix], m)
168
        }
169
        return
170
}
func @646:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

646
func(cls clause.Clause) {
647
                        whereClause, ok := cls.Expression.(clause.Where)
648
                        if !ok {
649
                                return
650
                        }
651
                        whereClause.Exprs = changeExprFunc(whereClause.Exprs)
652
                        cls.Expression = whereClause
653
                        db.Statement.Clauses["WHERE"] = cls
654
                }
func shardingMigrator.AutoMigrate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1209
func (s *shardingMigrator) AutoMigrate(dst ...any) (err error) {
1210
        sharding, ok := s.shardingMap[s.tableName(s.db, dst[0])]
1211
        if !ok {
1212
                defer (*tableSharding)(nil).ignore(s.db)() //nolint: revive // partial calling issue
1213
                return s.Migrator.AutoMigrate(dst...)
1214
        }
1215
1216
        stmt := &gorm.Statement{DB: sharding.DB}
1217
        if sharding.isIgnored(sharding.DB)() {
1218
                return s.dialector.Migrator(stmt.DB.Session(&gorm.Session{})).AutoMigrate(dst...)
1219
        }
1220
1221
        shardingDst, err := s.getShardingDst(sharding, dst...)
1222
        if err != nil {
1223
                return err
1224
        }
1225
1226
        defer sharding.ignore(sharding.DB)() //nolint: revive // partial calling issue
1227
        for _, sd := range shardingDst {
1228
                tx := stmt.DB.Session(&gorm.Session{}).Table(sd.table)
1229
                if err = s.dialector.Migrator(tx).AutoMigrate(sd.dst); err != nil {
1230
                        return err
1231
                }
1232
        }
1233
1234
        return
1235
}
func shardingMigrator.DropTable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1236
func (s *shardingMigrator) DropTable(dst ...any) (err error) {
1237
        sharding, ok := s.shardingMap[s.tableName(s.db, dst[0])]
1238
        if !ok {
1239
                defer (*tableSharding)(nil).ignore(s.db)() //nolint: revive // partial calling issue
1240
                return s.Migrator.DropTable(dst...)
1241
        }
1242
1243
        stmt := &gorm.Statement{DB: sharding.DB}
1244
        if sharding.isIgnored(sharding.DB)() {
1245
                return s.dialector.Migrator(stmt.DB.Session(&gorm.Session{})).DropTable(dst...)
1246
        }
1247
        shardingDst, err := s.getShardingDst(sharding, dst...)
1248
        if err != nil {
1249
                return err
1250
        }
1251
1252
        defer sharding.ignore(sharding.DB)() //nolint: revive // partial calling issue
1253
        for _, sd := range shardingDst {
1254
                tx := stmt.DB.Session(&gorm.Session{}).Table(sd.table)
1255
                if err = s.dialector.Migrator(tx).DropTable(sd.table); err != nil {
1256
                        return err
1257
                }
1258
        }
1259
1260
        return
1261
}
func @371:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

371
func(condition sqlparser.Node, tableName string, vars ...any) (suffix string, err error) {
372
                values := make([]any, 0, len(t.config.ShardingKeys))
373
                for _, key := range t.config.ShardingKeys {
374
                        val, err := t.nonInsertValue(condition, key, tableName, vars...)
375
                        if err != nil {
376
                                return "", db.AddError(err)
377
                        }
378
                        values = append(values, val)
379
                }
380
381
                suffix, err = t.shardingFunc(db.Statement.Context, values...)
382
                if err != nil {
383
                        return "", db.AddError(err)
384
                }
385
                return
386
        }
func DefaultTableSharding
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

95
func DefaultTableSharding(config TableShardingConfig) TableSharding {
96
        if utils.IsStrBlank(config.Table) {
97
                panic(errors.New("missing sharding table name"))
98
        }
99
        if len(config.ShardingKeys) == 0 {
100
                panic(errors.New("missing sharding keys"))
101
        }
102
        if !config.ShardingKeyByRawValue && (config.NumberOfShards <= 0 || config.NumberOfShards >= 100000) {
103
                panic(errors.New("invalid number of shards"))
104
        }
105
106
        shardingKeySet := utils.NewSet(config.ShardingKeys...)
107
        shardingPrimaryKey := ""
108
        isShardingPrimaryKey := false
109
        if shardingKeySet.Contains("id") || shardingKeySet.Contains("ID") ||
110
                shardingKeySet.Contains("iD") || shardingKeySet.Contains("Id") {
111
                if config.PrimaryKeyGenerator == nil {
112
                        panic(errors.New("sharding by primary key but primary key generator not found"))
113
                }
114
115
                isShardingPrimaryKey = true
116
                for _, key := range config.ShardingKeys {
117
                        if key == "id" || key == "ID" || key == "Id" || key == "iD" {
118
                                shardingPrimaryKey = key
119
                                break
120
                        }
121
                }
122
        }
123
124
        return &tableSharding{
125
                config:               config,
126
                isShardingPrimaryKey: isShardingPrimaryKey,
127
                shardingPrimaryKey:   shardingPrimaryKey,
128
                shardingTableCreated: make(map[string]struct{}, config.NumberOfShards),
129
        }
130
}
func @854:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

854
func(rv reflect.Value) (err error) {
855
                _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
856
                if !isZero {
857
                        return
858
                }
859
                if t.config.PrimaryKeyGenerator == nil {
860
                        return ErrIDGeneratorNotFound
861
                }
862
                id, err := t.config.PrimaryKeyGenerator.Next(idgen.GormTx(db))
863
                if err != nil {
864
                        return
865
                }
866
                return db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, id)
867
        }
func tableSharding.setPrimaryKeyByModel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

849
func (t *tableSharding) setPrimaryKeyByModel(db *gorm.DB, opt *tableShardingDispatchOption) (err error) {
850
        if !opt.isInsert || db.Statement.Model == nil ||
851
                db.Statement.Schema == nil || db.Statement.Schema.PrioritizedPrimaryField == nil {
852
                return
853
        }
854
        setPrimaryKeyFunc := func(rv reflect.Value) (err error) {
855
                _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
856
                if !isZero {
857
                        return
858
                }
859
                if t.config.PrimaryKeyGenerator == nil {
860
                        return ErrIDGeneratorNotFound
861
                }
862
                id, err := t.config.PrimaryKeyGenerator.Next(idgen.GormTx(db))
863
                if err != nil {
864
                        return
865
                }
866
                return db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, id)
867
        }
868
869
        switch db.Statement.ReflectValue.Kind() {
870
        case reflect.Slice, reflect.Array:
871
                for i := 0; i < db.Statement.ReflectValue.Len(); i++ {
872
                        rv := db.Statement.ReflectValue.Index(i)
873
                        if reflect.Indirect(rv).Kind() != reflect.Struct {
874
                                break
875
                        }
876
877
                        if err = setPrimaryKeyFunc(rv); err != nil {
878
                                return
879
                        }
880
                }
881
        case reflect.Struct:
882
                if err = setPrimaryKeyFunc(db.Statement.ReflectValue); err != nil {
883
                        return
884
                }
885
        }
886
887
        return
888
}
func @438:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

438
func(stmt *sqlparser.SelectStatement) (ok bool, err error) {
439
                        if stmt.Hint != nil && stmt.Hint.Value == "nosharding" {
440
                                return false, nil
441
                        }
442
443
                        switch tbl := stmt.FromItems.(type) {
444
                        case *sqlparser.TableName:
445
                                if tbl.TableName() != t.config.Table {
446
                                        return false, nil
447
                                }
448
                                suffix, e := getSuffix(stmt.Condition, t.config.Table, db.Statement.Vars...)
449
                                if e != nil {
450
                                        _ = db.AddError(e)
451
                                        return false, nil
452
                                }
453
                                oldTableName := tbl.TableName()
454
                                newTableName := oldTableName + suffix
455
                                stmt.FromItems = &sqlparser.TableName{Name: &sqlparser.Ident{Name: newTableName}}
456
                                stmt.OrderBy = t.replaceOrderByTableName(stmt.OrderBy, oldTableName, newTableName)
457
                                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
458
                                        _ = db.AddError(e)
459
                                        return false, nil
460
                                }
461
                        case *sqlparser.JoinClause:
462
                                tblx, _ := tbl.X.(*sqlparser.TableName)
463
                                tbly, _ := tbl.Y.(*sqlparser.TableName)
464
                                isXSharding := tblx != nil && tblx.TableName() == t.config.Table
465
                                isYSharding := tbly != nil && tbly.TableName() == t.config.Table
466
                                oldTableName := ""
467
                                switch {
468
                                case isXSharding:
469
                                        oldTableName = tblx.TableName()
470
                                case isYSharding:
471
                                        oldTableName = tbly.TableName()
472
                                default:
473
                                        return false, nil
474
                                }
475
                                suffix, e := getSuffix(stmt.Condition, oldTableName, db.Statement.Vars...)
476
                                if e != nil {
477
                                        _ = db.AddError(e)
478
                                        return false, nil
479
                                }
480
                                newTableName := oldTableName + suffix
481
                                stmt.OrderBy = t.replaceOrderByTableName(stmt.OrderBy, oldTableName, newTableName)
482
                                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
483
                                        _ = db.AddError(e)
484
                                        return false, nil
485
                                }
486
                                if e := t.replaceConstraint(tbl.Constraint, oldTableName, newTableName); err != nil {
487
                                        _ = db.AddError(e)
488
                                        return false, nil
489
                                }
490
                                if isXSharding {
491
                                        tblx.Name.Name = newTableName
492
                                } else {
493
                                        tbly.Name.Name = newTableName
494
                                }
495
                                if stmt.Columns != nil {
496
                                        for _, column := range *stmt.Columns {
497
                                                columnTbl, ok := column.Expr.(*sqlparser.QualifiedRef)
498
                                                if !ok || columnTbl.Table.Name != oldTableName {
499
                                                        continue
500
                                                }
501
                                                columnTbl.Table.Name = newTableName
502
                                        }
503
                                }
504
                        }
505
                        return true, nil
506
                }
func tableSharding.dispatchTableByModel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

299
func (t *tableSharding) dispatchTableByModel(db *gorm.DB, opts ...utils.OptionExtender) (otherTable, ok bool) {
300
        if db.Statement.Model == nil || utils.IsBlank(db.Statement.ReflectValue.Interface()) {
301
                return
302
        }
303
        if db.Statement.Table != t.config.Table {
304
                otherTable = true
305
                return
306
        }
307
        if t.shardingTableModel == nil {
308
                if _, ok := db.Statement.Model.(schema.Tabler); ok {
309
                        cloneModel := clone.Clone(db.Statement.Model)
310
                        t.shardingTableModel = cloneModel
311
                }
312
        }
313
314
        opt := utils.ApplyOptions[tableShardingDispatchOption](opts...)
315
        if t.isShardingPrimaryKey {
316
                if err := t.setPrimaryKeyByModel(db, opt); err != nil {
317
                        _ = db.AddError(err)
318
                        return
319
                }
320
        }
321
322
        reflectVal, ok := t.getModelReflectValue(db)
323
        if !ok {
324
                return
325
        }
326
        if err := t.checkDiffSuffixesByModel(db); err != nil {
327
                return
328
        }
329
330
        values := make([]any, 0, len(t.config.ShardingKeys))
331
        for _, key := range t.config.ShardingKeys {
332
                val := reflectVal.FieldByNameFunc(func(v string) bool { return strings.EqualFold(v, key) })
333
                if !val.IsValid() {
334
                        val, _ = utils.GetGormColumnValue(reflectVal, key)
335
                }
336
                if !val.IsValid() {
337
                        _ = db.AddError(ErrMissingShardingKey)
338
                        return
339
                }
340
                values = append(values, val.Interface())
341
        }
342
343
        suffix, err := t.shardingFunc(db.Statement.Context, values...)
344
        if err != nil {
345
                _ = db.AddError(err)
346
                return
347
        }
348
        // cannot parse suffix from model
349
        if utils.IsStrBlank(suffix) || suffix == constant.Underline {
350
                return false, false
351
        }
352
        if err = t.createTableIfNotExists(db, db.Statement.Table, suffix); err != nil {
353
                _ = db.AddError(err)
354
                return
355
        }
356
357
        db.Statement.Table = db.Statement.Table + suffix
358
        t.replaceStatementClauseAndSchema(db, opt)
359
        ok = true
360
        return
361
}
func shardingMigrator.getShardingDst
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1268
func (s *shardingMigrator) getShardingDst(sharding *tableSharding, src ...any) (dst []shardingDst, err error) {
1269
        for _, model := range src {
1270
                stmt := &gorm.Statement{DB: sharding.DB}
1271
                if err = stmt.Parse(model); err != nil {
1272
                        return
1273
                }
1274
1275
                // support sharding table
1276
                suffixes, err := sharding.suffixes()
1277
                if err != nil {
1278
                        return nil, err
1279
                }
1280
                if len(suffixes) == 0 {
1281
                        return nil, fmt.Errorf("sharding table:%s suffixes are empty", stmt.Table)
1282
                }
1283
                for _, suffix := range suffixes {
1284
                        dst = append(dst, shardingDst{
1285
                                table: stmt.Table + suffix,
1286
                                dst:   model,
1287
                        })
1288
                }
1289
        }
1290
        return
1291
}
func tableSharding.getModelReflectValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

890
func (t *tableSharding) getModelReflectValue(db *gorm.DB) (reflectVal reflect.Value, ok bool) {
891
        reflectVal = utils.IndirectValue(db.Statement.ReflectValue)
892
        if reflectVal.Kind() == reflect.Array || reflectVal.Kind() == reflect.Slice {
893
                if reflectVal.Len() == 0 {
894
                        return
895
                }
896
                reflectVal = utils.IndirectValue(reflectVal.Index(0))
897
        }
898
899
        if reflectVal.Kind() != reflect.Struct {
900
                return
901
        }
902
903
        return reflectVal, !utils.IsBlank(reflectVal.Interface())
904
}
func shardingMigrator.tableName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1292
func (s *shardingMigrator) tableName(db *gorm.DB, m any) (name string) {
1293
        if tabler, ok := m.(schema.Tabler); ok {
1294
                name = tabler.TableName()
1295
        }
1296
        if tabler, ok := m.(schema.TablerWithNamer); ok {
1297
                name = tabler.TableName(db.NamingStrategy)
1298
        }
1299
        namingStrategy := reflect.ValueOf(db.NamingStrategy)
1300
        if namingStrategy.CanConvert(gormSchemaEmbeddedNamer) {
1301
                name = reflect.Indirect(namingStrategy.Convert(gormSchemaEmbeddedNamer)).FieldByName("Table").String()
1302
        }
1303
        return
1304
}
func tableSharding.wrapDispatchTableBySQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

565
func (t *tableSharding) wrapDispatchTableBySQL(db *gorm.DB, opts ...utils.OptionExtender) {
566
        if ok, err := t.dispatchTableBySQL(db, opts...); err != nil || !ok {
567
                // not a dml
568
                if err != nil {
569
                        return
570
                }
571
                // not a sharding table
572
                if !ok {
573
                        // FIXME: reset sql parse result will get duplicated sql statement
574
                        // db.Statement.SQL = strings.Builder{}
575
                        // db.Statement.Vars = nil
576
                }
577
        }
578
}
func tableSharding.ignore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1001
func (t *tableSharding) ignore(db *gorm.DB) func() {
1002
        if _, ok := db.Statement.Settings.Load(shardingIgnoreStoreKey); ok {
1003
                return func() {}
1004
        }
1005
        db.Statement.Settings.Store(shardingIgnoreStoreKey, nil)
1006
        return func() {
1007
                db.Statement.Settings.Delete(shardingIgnoreStoreKey)
1008
        }
1009
}
func tableSharding.nonInsertValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

800
func (t *tableSharding) nonInsertValue(condition sqlparser.Node, key, tableName string, args ...any) (
801
        value any, err error) {
802
        found := false
803
        err = sqlparser.Walk(
804
                sqlparser.VisitFunc(func(node sqlparser.Node) (err error) {
805
                        n, ok := node.(*sqlparser.BinaryExpr)
806
                        if !ok {
807
                                return
808
                        }
809
                        if n.Op != sqlparser.EQ {
810
                                return
811
                        }
812
813
                        switch x := n.X.(type) {
814
                        case *sqlparser.Ident:
815
                                if x.Name != key {
816
                                        return
817
                                }
818
                        case *sqlparser.QualifiedRef:
819
                                if !ok || x.Table.Name != tableName || x.Column.Name != key {
820
                                        return
821
                                }
822
                        }
823
824
                        found = true
825
                        switch expr := n.Y.(type) {
826
                        case *sqlparser.BindExpr:
827
                                value = args[expr.Pos]
828
                        case *sqlparser.StringLit:
829
                                value = expr.Value
830
                        case *sqlparser.NumberLit:
831
                                value = expr.Value
832
                        default:
833
                                return sqlparser.ErrNotImplemented
834
                        }
835
836
                        return
837
                }),
838
                condition,
839
        )
840
        if err != nil {
841
                return
842
        }
843
        if !found {
844
                return nil, ErrMissingShardingKey
845
        }
846
        return
847
}
func tableSharding.defaultShardingFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1017
func (t *tableSharding) defaultShardingFunc() func(ctx context.Context, values ...any) (suffix string, err error) {
1018
        if !t.config.ShardingKeyByRawValue && t.config.NumberOfShards == 0 {
1019
                panic(errors.New("missing number_of_shards config"))
1020
        }
1021
        t.suffixFormat = constant.Underline
1022
1023
        switch {
1024
        case utils.IsStrNotBlank(t.config.CustomSuffix):
1025
                t.suffixFormat += t.config.CustomSuffix
1026
        case t.config.ShardingKeyByRawValue:
1027
                t.suffixFormat += "%s"
1028
        default:
1029
                t.suffixFormat += strings.Join(t.config.ShardingKeys, constant.Underline)
1030
        }
1031
1032
        numberOfShards := t.config.NumberOfShards
1033
        if !strings.Contains(t.suffixFormat, "%") {
1034
                if t.config.ShardingKeyByRawValue {
1035
                        t.suffixFormat += "_%s"
1036
                } else if numberOfShards < 10 {
1037
                        t.suffixFormat += "_%01d"
1038
                } else if numberOfShards < 100 {
1039
                        t.suffixFormat += "_%02d"
1040
                } else if numberOfShards < 1000 {
1041
                        t.suffixFormat += "_%03d"
1042
                } else if numberOfShards < 10000 {
1043
                        t.suffixFormat += "_%04d"
1044
                }
1045
        }
1046
1047
        switch {
1048
        case t.config.ShardingKeyByRawValue:
1049
                return func(ctx context.Context, values ...any) (suffix string, err error) {
1050
                        data := make([]string, 0, len(values))
1051
                        for _, value := range values {
1052
                                v, err := cast.ToStringE(value)
1053
                                if err != nil {
1054
                                        return "", err
1055
                                }
1056
                                data = append(data, v)
1057
                        }
1058
                        shardingKey := strings.Join(data, constant.Underline)
1059
                        return fmt.Sprintf("_%s", shardingKey), nil
1060
                }
1061
        case t.config.ShardingKeyExpr != nil:
1062
                numberOfShardsFloat64 := float64(numberOfShards)
1063
                return func(ctx context.Context, values ...any) (suffix string, err error) {
1064
                        params := make(map[string]any, len(t.config.ShardingKeys))
1065
                        for idx, column := range t.config.ShardingKeys {
1066
                                params[column] = values[idx]
1067
                        }
1068
1069
                        result, err := t.config.ShardingKeyExpr(ctx, params)
1070
                        if err != nil {
1071
                                return
1072
                        }
1073
                        shardingKey := int64(math.Mod(cast.ToFloat64(result), numberOfShardsFloat64))
1074
                        return fmt.Sprintf(t.suffixFormat, shardingKey), nil
1075
                }
1076
        default:
1077
                stringToByteSliceFunc := func(v string) (data []byte) {
1078
                        utils.IfAny(
1079
                                // number
1080
                                func() (ok bool) {
1081
                                        num := new(big.Float)
1082
                                        if _, ok = num.SetString(v); !ok {
1083
                                                return
1084
                                        }
1085
                                        gobEncoded, err := num.GobEncode()
1086
                                        if err != nil {
1087
                                                return false
1088
                                        }
1089
                                        data = gobEncoded
1090
                                        return
1091
                                },
1092
                                // uuid
1093
                                func() bool {
1094
                                        uid, err := uuid.Parse(v)
1095
                                        if err != nil {
1096
                                                return false
1097
                                        }
1098
                                        data = uid[:]
1099
                                        return true
1100
                                },
1101
                                // bytes
1102
                                func() bool { data = []byte(v); return true },
1103
                        )
1104
                        return
1105
                }
1106
                return func(ctx context.Context, values ...any) (suffix string, err error) {
1107
                        size := 0
1108
                        for _, value := range values {
1109
                                s := binary.Size(value)
1110
                                if s <= 0 {
1111
                                        s = int(unsafe.Sizeof(value))
1112
                                }
1113
                                size += s
1114
                        }
1115
                        w := new(bytes.Buffer)
1116
                        w.Grow(size)
1117
1118
                        for _, value := range values {
1119
                                var data any
1120
                                switch v := value.(type) {
1121
                                case int, *int:
1122
                                        data = utils.IntNarrow(cast.ToInt(v))
1123
                                case uint, *uint:
1124
                                        data = utils.UintNarrow(cast.ToUint(v))
1125
                                case []int:
1126
                                        data = make([]any, len(v))
1127
                                        for i := 0; i < len(v); i++ {
1128
                                                data.([]any)[i] = utils.IntNarrow(cast.ToInt(v))
1129
                                        }
1130
                                case []uint:
1131
                                        data = make([]any, len(v))
1132
                                        for i := 0; i < len(v); i++ {
1133
                                                data.([]any)[i] = utils.UintNarrow(cast.ToUint(v))
1134
                                        }
1135
                                case string:
1136
                                        data = stringToByteSliceFunc(v)
1137
                                case []byte:
1138
                                        data = stringToByteSliceFunc(utils.UnsafeBytesToString(v))
1139
                                case uuid.UUID:
1140
                                        data = v[:]
1141
                                default:
1142
                                        data = v
1143
                                }
1144
                                if err = binary.Write(w, binary.BigEndian, data); err != nil {
1145
                                        return
1146
                                }
1147
                        }
1148
1149
                        // checksum mod shards
1150
                        checksum := crc32.ChecksumIEEE(w.Bytes())
1151
                        shardingKey := uint64(checksum) % uint64(numberOfShards)
1152
                        suffix = fmt.Sprintf(t.suffixFormat, shardingKey)
1153
                        return
1154
                }
1155
        }
1156
}
func tableSharding.ShardingIDGen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

196
func (t *tableSharding) ShardingIDGen(ctx context.Context) (id uint64, err error) {
197
        if t.config.PrimaryKeyGenerator == nil {
198
                return 0, ErrIDGeneratorNotFound
199
        }
200
        return t.config.PrimaryKeyGenerator.Next()
201
}
func @1093:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1093
func() bool {
1094
                                        uid, err := uuid.Parse(v)
1095
                                        if err != nil {
1096
                                                return false
1097
                                        }
1098
                                        data = uid[:]
1099
                                        return true
1100
                                }
func @1106:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1106
func(ctx context.Context, values ...any) (suffix string, err error) {
1107
                        size := 0
1108
                        for _, value := range values {
1109
                                s := binary.Size(value)
1110
                                if s <= 0 {
1111
                                        s = int(unsafe.Sizeof(value))
1112
                                }
1113
                                size += s
1114
                        }
1115
                        w := new(bytes.Buffer)
1116
                        w.Grow(size)
1117
1118
                        for _, value := range values {
1119
                                var data any
1120
                                switch v := value.(type) {
1121
                                case int, *int:
1122
                                        data = utils.IntNarrow(cast.ToInt(v))
1123
                                case uint, *uint:
1124
                                        data = utils.UintNarrow(cast.ToUint(v))
1125
                                case []int:
1126
                                        data = make([]any, len(v))
1127
                                        for i := 0; i < len(v); i++ {
1128
                                                data.([]any)[i] = utils.IntNarrow(cast.ToInt(v))
1129
                                        }
1130
                                case []uint:
1131
                                        data = make([]any, len(v))
1132
                                        for i := 0; i < len(v); i++ {
1133
                                                data.([]any)[i] = utils.UintNarrow(cast.ToUint(v))
1134
                                        }
1135
                                case string:
1136
                                        data = stringToByteSliceFunc(v)
1137
                                case []byte:
1138
                                        data = stringToByteSliceFunc(utils.UnsafeBytesToString(v))
1139
                                case uuid.UUID:
1140
                                        data = v[:]
1141
                                default:
1142
                                        data = v
1143
                                }
1144
                                if err = binary.Write(w, binary.BigEndian, data); err != nil {
1145
                                        return
1146
                                }
1147
                        }
1148
1149
                        // checksum mod shards
1150
                        checksum := crc32.ChecksumIEEE(w.Bytes())
1151
                        shardingKey := uint64(checksum) % uint64(numberOfShards)
1152
                        suffix = fmt.Sprintf(t.suffixFormat, shardingKey)
1153
                        return
1154
                }
func tableSharding.createTableIfNotExists
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

951
func (t *tableSharding) createTableIfNotExists(db *gorm.DB, tableName, suffix string) (err error) {
952
        shardingTableName := tableName + suffix
953
        t.shardingTableCreatedMutex.RLock()
954
        if _, ok := t.shardingTableCreated[shardingTableName]; ok {
955
                t.shardingTableCreatedMutex.RUnlock()
956
                return
957
        }
958
        t.shardingTableCreatedMutex.RUnlock()
959
        t.shardingTableCreatedMutex.Lock()
960
        defer t.shardingTableCreatedMutex.Unlock()
961
962
        defer t.ignore(t.DB)() //nolint: revive // partial calling issue
963
        if t.DB.Migrator().HasTable(shardingTableName) {
964
                t.shardingTableCreated[shardingTableName] = struct{}{}
965
                return
966
        }
967
968
        model := db.Statement.Model
969
        if model == nil {
970
                model = t.shardingTableModel
971
        }
972
        if model == nil {
973
                return ErrShardingModelNotFound
974
        }
975
        tx := t.DB.Session(&gorm.Session{}).Table(shardingTableName)
976
        if err = db.Dialector.Migrator(tx).AutoMigrate(db.Statement.Model); err != nil {
977
                return err
978
        }
979
        t.shardingTableCreated[shardingTableName] = struct{}{}
980
        return
981
}
func @1080:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1080
func() (ok bool) {
1081
                                        num := new(big.Float)
1082
                                        if _, ok = num.SetString(v); !ok {
1083
                                                return
1084
                                        }
1085
                                        gobEncoded, err := num.GobEncode()
1086
                                        if err != nil {
1087
                                                return false
1088
                                        }
1089
                                        data = gobEncoded
1090
                                        return
1091
                                }
func tableSharding.dispatchTableBySQL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

364
func (t *tableSharding) dispatchTableBySQL(db *gorm.DB, opts ...utils.OptionExtender) (ok bool, err error) {
365
        expr, err := sqlparser.NewParser(strings.NewReader(db.Statement.SQL.String())).ParseStatement()
366
        if err != nil {
367
                // maybe not a dml, so we ignore this error
368
                return
369
        }
370
371
        getSuffix := func(condition sqlparser.Node, tableName string, vars ...any) (suffix string, err error) {
372
                values := make([]any, 0, len(t.config.ShardingKeys))
373
                for _, key := range t.config.ShardingKeys {
374
                        val, err := t.nonInsertValue(condition, key, tableName, vars...)
375
                        if err != nil {
376
                                return "", db.AddError(err)
377
                        }
378
                        values = append(values, val)
379
                }
380
381
                suffix, err = t.shardingFunc(db.Statement.Context, values...)
382
                if err != nil {
383
                        return "", db.AddError(err)
384
                }
385
                return
386
        }
387
388
        newSQL := ""
389
        switch stmt := expr.(type) {
390
        case *sqlparser.InsertStatement:
391
                if stmt.TableName.TableName() != t.config.Table {
392
                        return
393
                }
394
395
                suffix := ""
396
                for _, insertExpression := range stmt.Expressions {
397
                        values, id, e := t.insertValue(t.config.ShardingKeys, stmt.ColumnNames,
398
                                insertExpression.Exprs, db.Statement.Vars...)
399
                        if e != nil {
400
                                _ = db.AddError(e)
401
                                return
402
                        }
403
                        if t.isShardingPrimaryKey && id == 0 {
404
                                if t.config.PrimaryKeyGenerator == nil {
405
                                        _ = db.AddError(ErrIDGeneratorNotFound)
406
                                        return
407
                                }
408
                                if id, e = t.config.PrimaryKeyGenerator.Next(idgen.GormTx(db)); e != nil {
409
                                        _ = db.AddError(e)
410
                                        return
411
                                }
412
                                stmt.ColumnNames = append(stmt.ColumnNames, &sqlparser.Ident{Name: "id"})
413
                                insertExpression.Exprs = append(insertExpression.Exprs, &sqlparser.NumberLit{Value: cast.ToString(id)})
414
                                values, _, _ = t.insertValue(t.config.ShardingKeys, stmt.ColumnNames,
415
                                        insertExpression.Exprs, db.Statement.Vars...)
416
                        }
417
418
                        subSuffix, e := t.shardingFunc(db.Statement.Context, values...)
419
                        if e != nil {
420
                                _ = db.AddError(e)
421
                                return
422
                        }
423
424
                        if suffix != "" && suffix != subSuffix {
425
                                _ = db.AddError(ErrDiffSuffixDML)
426
                                return
427
                        }
428
                        suffix = subSuffix
429
                }
430
                // FIXME: could not find the table schema to migrate
431
                if e := t.createTableIfNotExists(db, db.Statement.Table, suffix); e != nil {
432
                        _ = db.AddError(e)
433
                        return
434
                }
435
                stmt.TableName = &sqlparser.TableName{Name: &sqlparser.Ident{Name: stmt.TableName.TableName() + suffix}}
436
                newSQL = stmt.String()
437
        case *sqlparser.SelectStatement:
438
                parseSelectStatementFunc := func(stmt *sqlparser.SelectStatement) (ok bool, err error) {
439
                        if stmt.Hint != nil && stmt.Hint.Value == "nosharding" {
440
                                return false, nil
441
                        }
442
443
                        switch tbl := stmt.FromItems.(type) {
444
                        case *sqlparser.TableName:
445
                                if tbl.TableName() != t.config.Table {
446
                                        return false, nil
447
                                }
448
                                suffix, e := getSuffix(stmt.Condition, t.config.Table, db.Statement.Vars...)
449
                                if e != nil {
450
                                        _ = db.AddError(e)
451
                                        return false, nil
452
                                }
453
                                oldTableName := tbl.TableName()
454
                                newTableName := oldTableName + suffix
455
                                stmt.FromItems = &sqlparser.TableName{Name: &sqlparser.Ident{Name: newTableName}}
456
                                stmt.OrderBy = t.replaceOrderByTableName(stmt.OrderBy, oldTableName, newTableName)
457
                                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
458
                                        _ = db.AddError(e)
459
                                        return false, nil
460
                                }
461
                        case *sqlparser.JoinClause:
462
                                tblx, _ := tbl.X.(*sqlparser.TableName)
463
                                tbly, _ := tbl.Y.(*sqlparser.TableName)
464
                                isXSharding := tblx != nil && tblx.TableName() == t.config.Table
465
                                isYSharding := tbly != nil && tbly.TableName() == t.config.Table
466
                                oldTableName := ""
467
                                switch {
468
                                case isXSharding:
469
                                        oldTableName = tblx.TableName()
470
                                case isYSharding:
471
                                        oldTableName = tbly.TableName()
472
                                default:
473
                                        return false, nil
474
                                }
475
                                suffix, e := getSuffix(stmt.Condition, oldTableName, db.Statement.Vars...)
476
                                if e != nil {
477
                                        _ = db.AddError(e)
478
                                        return false, nil
479
                                }
480
                                newTableName := oldTableName + suffix
481
                                stmt.OrderBy = t.replaceOrderByTableName(stmt.OrderBy, oldTableName, newTableName)
482
                                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
483
                                        _ = db.AddError(e)
484
                                        return false, nil
485
                                }
486
                                if e := t.replaceConstraint(tbl.Constraint, oldTableName, newTableName); err != nil {
487
                                        _ = db.AddError(e)
488
                                        return false, nil
489
                                }
490
                                if isXSharding {
491
                                        tblx.Name.Name = newTableName
492
                                } else {
493
                                        tbly.Name.Name = newTableName
494
                                }
495
                                if stmt.Columns != nil {
496
                                        for _, column := range *stmt.Columns {
497
                                                columnTbl, ok := column.Expr.(*sqlparser.QualifiedRef)
498
                                                if !ok || columnTbl.Table.Name != oldTableName {
499
                                                        continue
500
                                                }
501
                                                columnTbl.Table.Name = newTableName
502
                                        }
503
                                }
504
                        }
505
                        return true, nil
506
                }
507
                for compound := stmt; compound != nil; compound = compound.Compound {
508
                        if ok, err = parseSelectStatementFunc(compound); !ok || err != nil {
509
                                return
510
                        }
511
                }
512
513
                newSQL = stmt.String()
514
515
        case *sqlparser.UpdateStatement:
516
                if stmt.TableName.TableName() != t.config.Table {
517
                        return
518
                }
519
520
                suffix, e := getSuffix(stmt.Condition, t.config.Table, db.Statement.Vars...)
521
                if e != nil {
522
                        _ = db.AddError(e)
523
                        return
524
                }
525
526
                oldTableName := stmt.TableName.TableName()
527
                newTableName := oldTableName + suffix
528
                stmt.TableName = &sqlparser.TableName{Name: &sqlparser.Ident{Name: newTableName}}
529
                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
530
                        _ = db.AddError(e)
531
                        return false, nil
532
                }
533
                newSQL = stmt.String()
534
        case *sqlparser.DeleteStatement:
535
                if stmt.TableName.TableName() != t.config.Table {
536
                        return
537
                }
538
539
                suffix, e := getSuffix(stmt.Condition, t.config.Table, db.Statement.Vars...)
540
                if e != nil {
541
                        _ = db.AddError(e)
542
                        return
543
                }
544
545
                oldTableName := stmt.TableName.TableName()
546
                newTableName := oldTableName + suffix
547
                stmt.TableName = &sqlparser.TableName{Name: &sqlparser.Ident{Name: newTableName}}
548
                if e := t.replaceCondition(stmt.Condition, oldTableName, newTableName); err != nil {
549
                        _ = db.AddError(e)
550
                        return false, nil
551
                }
552
                newSQL = stmt.String()
553
        default:
554
                _ = db.AddError(sqlparser.ErrNotImplemented)
555
                return
556
        }
557
558
        sb := strings.Builder{}
559
        sb.Grow(len(newSQL))
560
        sb.WriteString(newSQL)
561
        db.Statement.SQL = sb
562
563
        return true, nil
564
}
func @580:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

580
func(src []clause.Expression) (dst []clause.Expression) {
581
                changeTableFunc := func(src any) (dst any, ok bool) {
582
                        switch col := src.(type) {
583
                        case clause.Column:
584
                                if col.Table == t.config.Table {
585
                                        col.Table = db.Statement.Table
586
                                        return col, true
587
                                }
588
                        case clause.Table:
589
                                if col.Name == t.config.Table {
590
                                        col.Name = db.Statement.Table
591
                                        return col, true
592
                                }
593
                        }
594
                        return
595
                }
596
                dst = make([]clause.Expression, 0, len(src))
597
                for _, srcExpr := range src {
598
                        switch expr := srcExpr.(type) {
599
                        case clause.IN:
600
                                if col, ok := changeTableFunc(expr.Column); ok {
601
                                        expr.Column = col
602
                                }
603
                                dst = append(dst, expr)
604
                        case clause.Eq:
605
                                if col, ok := changeTableFunc(expr.Column); ok {
606
                                        expr.Column = col
607
                                }
608
                                dst = append(dst, expr)
609
                        case clause.Neq:
610
                                if col, ok := changeTableFunc(expr.Column); ok {
611
                                        expr.Column = col
612
                                }
613
                                dst = append(dst, expr)
614
                        case clause.Gt:
615
                                if col, ok := changeTableFunc(expr.Column); ok {
616
                                        expr.Column = col
617
                                }
618
                                dst = append(dst, expr)
619
                        case clause.Gte:
620
                                if col, ok := changeTableFunc(expr.Column); ok {
621
                                        expr.Column = col
622
                                }
623
                                dst = append(dst, expr)
624
                        case clause.Lt:
625
                                if col, ok := changeTableFunc(expr.Column); ok {
626
                                        expr.Column = col
627
                                }
628
                                dst = append(dst, expr)
629
                        case clause.Lte:
630
                                if col, ok := changeTableFunc(expr.Column); ok {
631
                                        expr.Column = col
632
                                }
633
                                dst = append(dst, expr)
634
                        case clause.Like:
635
                                if col, ok := changeTableFunc(expr.Column); ok {
636
                                        expr.Column = col
637
                                }
638
                                dst = append(dst, expr)
639
                        default:
640
                                dst = append(dst, expr)
641
                        }
642
                }
643
                return
644
        }
func tableSharding.insertValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

731
func (t *tableSharding) insertValue(keys []string, names []*sqlparser.Ident, exprs []sqlparser.Expr, args ...any) (
732
        values []any, id uint64, err error) {
733
        if len(names) != len(exprs) {
734
                return nil, 0, ErrColumnAndExprMisMatch
735
        }
736
737
        for _, key := range keys {
738
                found := false
739
                isPrimaryKey := key == t.shardingPrimaryKey
740
                for i, name := range names {
741
                        if name.Name != key {
742
                                continue
743
                        }
744
745
                        switch expr := exprs[i].(type) {
746
                        case *sqlparser.BindExpr:
747
                                if !isPrimaryKey {
748
                                        values = append(values, args[expr.Pos])
749
                                } else {
750
                                        switch v := args[expr.Pos].(type) {
751
                                        case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string:
752
                                                if id, err = cast.ToUint64E(v); err != nil {
753
                                                        return nil, 0, errors.Wrapf(err, "parse id as uint64 failed [%v]", v)
754
                                                }
755
                                        default:
756
                                                return nil, 0, ErrInvalidID
757
                                        }
758
                                        if id != 0 {
759
                                                values = append(values, args[expr.Pos])
760
                                        }
761
                                }
762
                        case *sqlparser.StringLit:
763
                                if !isPrimaryKey {
764
                                        values = append(values, expr.Value)
765
                                } else {
766
                                        if id, err = cast.ToUint64E(expr.Value); err != nil {
767
                                                return nil, 0, errors.Wrapf(err, "parse id as uint64 failed [%s]", expr.Value)
768
                                        }
769
                                        if id != 0 {
770
                                                values = append(values, expr.Value)
771
                                        }
772
                                }
773
                        case *sqlparser.NumberLit:
774
                                if !isPrimaryKey {
775
                                        values = append(values, expr.Value)
776
                                } else {
777
                                        if id, err = strconv.ParseUint(expr.Value, 10, 64); err != nil {
778
                                                return nil, 0, errors.Wrapf(err,
779
                                                        "parse id as uint64 failed [%s]", expr.Value)
780
                                        }
781
                                        if id != 0 {
782
                                                values = append(values, expr.Value)
783
                                        }
784
                                }
785
                        default:
786
                                return nil, 0, sqlparser.ErrNotImplemented
787
                        }
788
789
                        found = true
790
                        break
791
                }
792
                if !found && !isPrimaryKey {
793
                        return nil, 0, ErrMissingShardingKey
794
                }
795
        }
796
797
        return
798
}
func tableSharding.ShardingByValues
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

172
func (t *tableSharding) ShardingByValues(ctx context.Context, src []map[string]any) (
173
        dst map[string][]map[string]any, err error) {
174
        dst = make(map[string][]map[string]any, len(t.config.ShardingKeys))
175
        for _, col := range src {
176
                values := make([]any, 0, len(col))
177
                for _, k := range t.config.ShardingKeys {
178
                        value, ok := col[k]
179
                        if !ok {
180
                                return dst, errors.Errorf("sharding key not found [column[%s]]", k)
181
                        }
182
                        if k == t.shardingPrimaryKey && utils.IsBlank(value) {
183
                                return dst, ErrInvalidID
184
                        }
185
                        values = append(values, value)
186
                }
187
                suffix, err := t.shardingFunc(ctx, values...)
188
                if err != nil {
189
                        return dst, err
190
                }
191
                dst[suffix] = append(dst[suffix], col)
192
        }
193
        return
194
}
func @655:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

655
func(cls clause.Clause) {
656
                        fromClause, ok := cls.Expression.(clause.From)
657
                        if !ok {
658
                                return
659
                        }
660
                        tables := make([]clause.Table, 0, len(fromClause.Tables))
661
                        for _, table := range fromClause.Tables {
662
                                if table.Name == t.config.Table {
663
                                        table.Name = db.Statement.Table
664
                                        tables = append(tables, table)
665
                                } else {
666
                                        tables = append(tables, table)
667
                                }
668
                        }
669
                        fromClause.Tables = tables
670
                        cls.Expression = fromClause
671
                        db.Statement.Clauses["FROM"] = cls
672
                }
func @581:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

581
func(src any) (dst any, ok bool) {
582
                        switch col := src.(type) {
583
                        case clause.Column:
584
                                if col.Table == t.config.Table {
585
                                        col.Table = db.Statement.Table
586
                                        return col, true
587
                                }
588
                        case clause.Table:
589
                                if col.Name == t.config.Table {
590
                                        col.Name = db.Statement.Table
591
                                        return col, true
592
                                }
593
                        }
594
                        return
595
                }
func @241:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

241
func() bool {
242
                        callbacks.BuildCreateSQL(db)
243
                        t.wrapDispatchTableBySQL(db, tableShardingIsInsert())
244
                        return true
245
                }
func @263:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

263
func() bool {
264
                        callbacks.BuildUpdateSQL(db)
265
                        t.wrapDispatchTableBySQL(db)
266
                        return true
267
                }
func shardingDialector.SavePoint
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1187
func (s shardingDialector) SavePoint(tx *gorm.DB, name string) error {
1188
        if savePointer, ok := s.Dialector.(gorm.SavePointerDialectorInterface); ok {
1189
                return savePointer.SavePoint(tx, name)
1190
        } else {
1191
                return gorm.ErrUnsupportedDriver
1192
        }
1193
}
func shardingDialector.RollbackTo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1194
func (s shardingDialector) RollbackTo(tx *gorm.DB, name string) error {
1195
        if savePointer, ok := s.Dialector.(gorm.SavePointerDialectorInterface); ok {
1196
                return savePointer.RollbackTo(tx, name)
1197
        } else {
1198
                return gorm.ErrUnsupportedDriver
1199
        }
1200
}
func @674:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

674
func(cls clause.Clause) {
675
                        _, ok := cls.Expression.(clause.OrderBy)
676
                        if !ok {
677
                                return
678
                        }
679
                }
func @284:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

284
func() bool { ok1, ok2 := t.dispatchTableByModel(db); return ok1 || ok2 }
func @285:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

285
func() bool { t.wrapDispatchTableBySQL(db); return true }
func @1003:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/plugins/table_sharding.go:

1003
func() {}
Package Overview: github.com/wfusion/gofusion/db/softdelete 59.0%

Please select a function to see what's left for testing.

deletedDeleteClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 8/8
@22:27(...) github.com/wfusion/gofusion/db/softdelete/deletedat.go 100.0% 4/4
TimestampUpdateClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 2/2
@20:3(...) github.com/wfusion/gofusion/db/softdelete/types.go 100.0% 2/2
@24:25(...) github.com/wfusion/gofusion/db/softdelete/deletedat.go 100.0% 2/2
@18:3(...) github.com/wfusion/gofusion/db/softdelete/types.go 100.0% 2/2
IsClausesWithSoftDelete(...) github.com/wfusion/gofusion/db/softdelete/types.go 100.0% 2/2
@21:3(...) github.com/wfusion/gofusion/db/softdelete/types.go 100.0% 2/2
deletedUpdateClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 2/2
@19:3(...) github.com/wfusion/gofusion/db/softdelete/types.go 100.0% 2/2
PatchGormDeleteAt(...) github.com/wfusion/gofusion/db/softdelete/deletedat.go 100.0% 2/2
Timestamp.UpdateClauses(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 1/1
Timestamp.QueryClauses(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 1/1
Timestamp.DeleteClauses(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 1/1
Deleted.DeleteClauses(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 1/1
Timestamp.Scan(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 1/1
Deleted.QueryClauses(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 1/1
Deleted.Value(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 1/1
Deleted.UpdateClauses(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 1/1
TimestampDeleteClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 80.0% 8/10
Deleted.Scan(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 80.0% 4/5
deletedQueryClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 66.7% 8/12
TimestampQueryClause.ModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 66.7% 8/12
Timestamp.Value(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 66.7% 2/3
parseStatusZeroValueTag(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 50.0% 2/4
parseTimestampZeroValueTag(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 50.0% 2/4
gormSoftDeleteDeleteClauseModifyStatement(...) github.com/wfusion/gofusion/db/softdelete/deletedat.go 0.0% 0/10
Timestamp.UnmarshalJSON(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 0.0% 0/7
Deleted.UnmarshalJSON(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 0.0% 0/7
Timestamp.MarshalJSON(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 0.0% 0/3
deletedQueryClause.Name(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 0.0% 0/1
TimestampQueryClause.Name(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 0.0% 0/1
deletedDeleteClause.Name(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 0.0% 0/1
TimestampDeleteClause.Name(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 0.0% 0/1
Deleted.MarshalJSON(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 0.0% 0/1
deletedUpdateClause.Name(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 0.0% 0/1
TimestampUpdateClause.Name(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 0.0% 0/1
TimestampUpdateClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
TimestampUpdateClause.Build(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
deletedUpdateClause.Build(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
TimestampDeleteClause.Build(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
TimestampDeleteClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
deletedQueryClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
TimestampQueryClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
TimestampQueryClause.Build(...) github.com/wfusion/gofusion/db/softdelete/timestamp.go 100.0% 0/0
deletedUpdateClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
deletedDeleteClause.Build(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
deletedDeleteClause.MergeClause(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
deletedQueryClause.Build(...) github.com/wfusion/gofusion/db/softdelete/deleted.go 100.0% 0/0
func deletedDeleteClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

125
func (s deletedDeleteClause) ModifyStatement(stmt *gorm.Statement) {
126
        deleted := true
127
        setClauses := clause.Set{{Column: clause.Column{Name: s.Field.DBName}, Value: deleted}}
128
        if clauses, ok := stmt.Clauses[setClauses.Name()]; ok {
129
                if exprClauses, ok := clauses.Expression.(clause.Set); ok {
130
                        setClauses = append(setClauses, exprClauses...)
131
                }
132
        }
133
        stmt.AddClause(setClauses)
134
        stmt.SetColumn(s.Field.DBName, deleted, true)
135
136
        deletedQueryClause(s).ModifyStatement(stmt)
137
}
func @22:27
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deletedat.go:

22
func() {
23
                pid := syscall.Getpid()
24
                _, err := utils.Catch(func() {
25
                        patches = gomonkey.ApplyMethod(gorm.SoftDeleteDeleteClause{},
26
                                "ModifyStatement", gormSoftDeleteDeleteClauseModifyStatement)
27
                        log.Printf("%v [Gofusion] %s patch gorm.SoftDeleteDeleteClause success", pid, config.ComponentDB)
28
                })
29
                if err != nil {
30
                        log.Printf("%v [Gofusion] %s patch gorm.SoftDeleteDeleteClause failed: %s",
31
                                pid, config.ComponentDB, errors.Cause(err))
32
                }
33
        }
func TimestampUpdateClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

104
func (t TimestampUpdateClause) ModifyStatement(stmt *gorm.Statement) {
105
        if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped {
106
                TimestampQueryClause(t).ModifyStatement(stmt)
107
        }
108
}
func @20:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/types.go:

20
func() (ok bool) { _, withSoftDelete = clauses[timestampEnabledFlag]; return withSoftDelete }
func @24:25
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deletedat.go:

24
func() {
25
                        patches = gomonkey.ApplyMethod(gorm.SoftDeleteDeleteClause{},
26
                                "ModifyStatement", gormSoftDeleteDeleteClauseModifyStatement)
27
                        log.Printf("%v [Gofusion] %s patch gorm.SoftDeleteDeleteClause success", pid, config.ComponentDB)
28
                }
func @18:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/types.go:

18
func() (ok bool) { _, withSoftDelete = clauses[defaultEnabledFlag]; return withSoftDelete }
func IsClausesWithSoftDelete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/types.go:

16
func IsClausesWithSoftDelete(clauses map[string]clause.Clause) (withSoftDelete bool) {
17
        utils.IfAny(
18
                func() (ok bool) { _, withSoftDelete = clauses[defaultEnabledFlag]; return withSoftDelete },
19
                func() (ok bool) { _, withSoftDelete = clauses[statusEnabledFlag]; return withSoftDelete },
20
                func() (ok bool) { _, withSoftDelete = clauses[timestampEnabledFlag]; return withSoftDelete },
21
                func() (ok bool) { _, withSoftDelete = clauses[deletedAtEnabledFlag]; return withSoftDelete },
22
        )
23
        return
24
}
func @21:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/types.go:

21
func() (ok bool) { _, withSoftDelete = clauses[deletedAtEnabledFlag]; return withSoftDelete }
func deletedUpdateClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

103
func (s deletedUpdateClause) ModifyStatement(stmt *gorm.Statement) {
104
        if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped {
105
                deletedQueryClause(s).ModifyStatement(stmt)
106
        }
107
}
func @19:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/types.go:

19
func() (ok bool) { _, withSoftDelete = clauses[statusEnabledFlag]; return withSoftDelete }
func PatchGormDeleteAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deletedat.go:

21
func PatchGormDeleteAt() (patches *gomonkey.Patches) {
22
        PatchGormDeleteAtOnce.Do(func() {
23
                pid := syscall.Getpid()
24
                _, err := utils.Catch(func() {
25
                        patches = gomonkey.ApplyMethod(gorm.SoftDeleteDeleteClause{},
26
                                "ModifyStatement", gormSoftDeleteDeleteClauseModifyStatement)
27
                        log.Printf("%v [Gofusion] %s patch gorm.SoftDeleteDeleteClause success", pid, config.ComponentDB)
28
                })
29
                if err != nil {
30
                        log.Printf("%v [Gofusion] %s patch gorm.SoftDeleteDeleteClause failed: %s",
31
                                pid, config.ComponentDB, errors.Cause(err))
32
                }
33
        })
34
35
        return
36
}
func Timestamp.UpdateClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

88
func (Timestamp) UpdateClauses(f *schema.Field) []clause.Interface {
89
        return []clause.Interface{TimestampUpdateClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
90
}
func Timestamp.QueryClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

49
func (Timestamp) QueryClauses(f *schema.Field) []clause.Interface {
50
        return []clause.Interface{TimestampQueryClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
51
}
func Timestamp.DeleteClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

110
func (Timestamp) DeleteClauses(f *schema.Field) []clause.Interface {
111
        return []clause.Interface{TimestampDeleteClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
112
}
func Deleted.DeleteClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

109
func (Deleted) DeleteClauses(f *schema.Field) []clause.Interface {
110
        return []clause.Interface{deletedDeleteClause{Field: f, ZeroValue: parseStatusZeroValueTag(f)}}
111
}
func Timestamp.Scan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

19
func (t *Timestamp) Scan(value any) error {
20
        return (*sql.NullInt64)(t).Scan(value)
21
}
func Deleted.QueryClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

47
func (Deleted) QueryClauses(f *schema.Field) []clause.Interface {
48
        return []clause.Interface{deletedQueryClause{Field: f, ZeroValue: parseStatusZeroValueTag(f)}}
49
}
func Deleted.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

27
func (s Deleted) Value() (driver.Value, error) {
28
        return bool(s), nil
29
}
func Deleted.UpdateClauses
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

87
func (Deleted) UpdateClauses(f *schema.Field) []clause.Interface {
88
        return []clause.Interface{deletedUpdateClause{Field: f, ZeroValue: parseStatusZeroValueTag(f)}}
89
}
func TimestampDeleteClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

126
func (t TimestampDeleteClause) ModifyStatement(stmt *gorm.Statement) {
127
        if stmt.Statement.Unscoped || stmt.SQL.Len() > 0 {
128
                return
129
        }
130
131
        curTimestamp := utils.GetTimeStamp(stmt.DB.NowFunc())
132
        setClauses := clause.Set{{Column: clause.Column{Name: t.Field.DBName}, Value: curTimestamp}}
133
        if clauses, ok := stmt.Clauses[setClauses.Name()]; ok {
134
                if exprClauses, ok := clauses.Expression.(clause.Set); ok {
135
                        setClauses = append(setClauses, exprClauses...)
136
                }
137
        }
138
        stmt.AddClause(setClauses)
139
        stmt.SetColumn(t.Field.DBName, curTimestamp, true)
140
141
        TimestampQueryClause(t).ModifyStatement(stmt)
142
}
func Deleted.Scan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

17
func (s *Deleted) Scan(value any) (err error) {
18
        var b bool
19
        if err = convertAssignRows(&b, value, nil); err != nil {
20
                return
21
        }
22
        *s = Deleted(b)
23
        return
24
}
func deletedQueryClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

63
func (s deletedQueryClause) ModifyStatement(stmt *gorm.Statement) {
64
        if _, ok := stmt.Clauses[statusEnabledFlag]; ok || stmt.Statement.Unscoped {
65
                return
66
        }
67
68
        if c, ok := stmt.Clauses["WHERE"]; ok {
69
                if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) >= 1 {
70
                        for _, expr := range where.Exprs {
71
                                if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 {
72
                                        where.Exprs = []clause.Expression{clause.And(where.Exprs...)}
73
                                        c.Expression = where
74
                                        stmt.Clauses["WHERE"] = c
75
                                        break
76
                                }
77
                        }
78
                }
79
        }
80
81
        stmt.AddClause(clause.Where{Exprs: []clause.Expression{
82
                clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: s.Field.DBName}, Value: s.ZeroValue},
83
        }})
84
        stmt.Clauses[statusEnabledFlag] = clause.Clause{}
85
}
func TimestampQueryClause.ModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

65
func (t TimestampQueryClause) ModifyStatement(stmt *gorm.Statement) {
66
        if _, ok := stmt.Clauses[timestampEnabledFlag]; ok || stmt.Statement.Unscoped {
67
                return
68
        }
69
        if c, ok := stmt.Clauses["WHERE"]; ok {
70
                if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) >= 1 {
71
                        for _, expr := range where.Exprs {
72
                                if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 {
73
                                        where.Exprs = []clause.Expression{clause.And(where.Exprs...)}
74
                                        c.Expression = where
75
                                        stmt.Clauses["WHERE"] = c
76
                                        break
77
                                }
78
                        }
79
                }
80
        }
81
82
        stmt.AddClause(clause.Where{Exprs: []clause.Expression{
83
                clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: t.Field.DBName}, Value: t.ZeroValue},
84
        }})
85
        stmt.Clauses[timestampEnabledFlag] = clause.Clause{}
86
}
func Timestamp.Value
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

24
func (t Timestamp) Value() (driver.Value, error) {
25
        if !t.Valid {
26
                return nil, nil
27
        }
28
        return t.Int64, nil
29
}
func parseStatusZeroValueTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

139
func parseStatusZeroValueTag(f *schema.Field) (s Deleted) {
140
        if v, ok := f.TagSettings["ZEROVALUE"]; ok {
141
                if vv, err := strconv.ParseBool(v); err == nil {
142
                        return Deleted(vv)
143
                }
144
        }
145
        return Deleted(false)
146
}
func parseTimestampZeroValueTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

144
func parseTimestampZeroValueTag(f *schema.Field) sql.NullInt64 {
145
        if v, ok := f.TagSettings["ZEROVALUE"]; ok {
146
                if vv, err := strconv.ParseInt(v, 10, 64); err == nil {
147
                        return sql.NullInt64{Int64: vv, Valid: true}
148
                }
149
        }
150
        return sql.NullInt64{Valid: false}
151
}
func gormSoftDeleteDeleteClauseModifyStatement
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deletedat.go:

38
func gormSoftDeleteDeleteClauseModifyStatement(sd gorm.SoftDeleteDeleteClause, stmt *gorm.Statement) {
39
        if stmt.Statement.Unscoped || stmt.SQL.Len() > 0 {
40
                return
41
        }
42
43
        curTime := stmt.DB.NowFunc()
44
        setClauses := clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: curTime}}
45
        if clauses, ok := stmt.Clauses[setClauses.Name()]; ok {
46
                if exprClauses, ok := clauses.Expression.(clause.Set); ok {
47
                        setClauses = append(setClauses, exprClauses...)
48
                }
49
        }
50
        stmt.AddClause(setClauses)
51
        stmt.SetColumn(sd.Field.DBName, curTime, true)
52
53
        gorm.SoftDeleteQueryClause(sd).ModifyStatement(stmt)
54
}
func Timestamp.UnmarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

37
func (t *Timestamp) UnmarshalJSON(bs []byte) error {
38
        if string(bs) == "null" {
39
                t.Valid = false
40
                return nil
41
        }
42
        err := json.Unmarshal(bs, &t.Int64)
43
        if err == nil {
44
                t.Valid = true
45
        }
46
        return err
47
}
func Deleted.UnmarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

34
func (s *Deleted) UnmarshalJSON(bs []byte) error {
35
        if string(bs) == "null" {
36
                return nil
37
        }
38
        var b bool
39
        err := json.Unmarshal(bs, &b)
40
        if err == nil {
41
                *s = Deleted(b)
42
        }
43
44
        return err
45
}
func Timestamp.MarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

31
func (t Timestamp) MarshalJSON() ([]byte, error) {
32
        if t.Valid {
33
                return json.Marshal(t.Int64)
34
        }
35
        return json.Marshal(nil)
36
}
func deletedQueryClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

56
func (s deletedQueryClause) Name() string {
57
        return ""
58
}
func TimestampQueryClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

58
func (t TimestampQueryClause) Name() string {
59
        return ""
60
}
func deletedDeleteClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

118
func (s deletedDeleteClause) Name() string {
119
        return ""
120
}
func TimestampDeleteClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

119
func (t TimestampDeleteClause) Name() string {
120
        return ""
121
}
func Deleted.MarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

31
func (s Deleted) MarshalJSON() ([]byte, error) {
32
        return json.Marshal(bool(s))
33
}
func deletedUpdateClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

96
func (s deletedUpdateClause) Name() string {
97
        return ""
98
}
func TimestampUpdateClause.Name
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

97
func (t TimestampUpdateClause) Name() string {
98
        return ""
99
}
func TimestampUpdateClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

102
func (t TimestampUpdateClause) MergeClause(*clause.Clause) {
103
}
func TimestampUpdateClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

100
func (t TimestampUpdateClause) Build(clause.Builder) {
101
}
func deletedUpdateClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

99
func (s deletedUpdateClause) Build(clause.Builder) {
100
}
func TimestampDeleteClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

122
func (t TimestampDeleteClause) Build(clause.Builder) {
123
}
func TimestampDeleteClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

124
func (t TimestampDeleteClause) MergeClause(*clause.Clause) {
125
}
func deletedQueryClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

61
func (s deletedQueryClause) MergeClause(*clause.Clause) {
62
}
func TimestampQueryClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

63
func (t TimestampQueryClause) MergeClause(*clause.Clause) {
64
}
func TimestampQueryClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/timestamp.go:

61
func (t TimestampQueryClause) Build(clause.Builder) {
62
}
func deletedUpdateClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

101
func (s deletedUpdateClause) MergeClause(*clause.Clause) {
102
}
func deletedDeleteClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

121
func (s deletedDeleteClause) Build(clause.Builder) {
122
}
func deletedDeleteClause.MergeClause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

123
func (s deletedDeleteClause) MergeClause(*clause.Clause) {
124
}
func deletedQueryClause.Build
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/db/softdelete/deleted.go:

59
func (s deletedQueryClause) Build(clause.Builder) {
60
}
Package Overview: github.com/wfusion/gofusion/http 68.3%

Please select a function to see what's left for testing.

lookupFieldByStruct(...) github.com/wfusion/gofusion/http/router.go 100.0% 20/20
addClient(...) github.com/wfusion/gofusion/http/construct.go 100.0% 14/14
Construct(...) github.com/wfusion/gofusion/http/construct.go 100.0% 14/14
addI18n(...) github.com/wfusion/gofusion/http/construct.go 100.0% 10/10
@223:9(...) github.com/wfusion/gofusion/http/construct.go 100.0% 8/8
@177:9(...) github.com/wfusion/gofusion/http/construct.go 100.0% 6/6
router.checkParamType(...) github.com/wfusion/gofusion/http/router.go 100.0% 4/4
@498:8(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.Any(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.rspError(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.wrapHandlerFunc(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.Config(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.POST(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
router.GET(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
@445:8(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
@62:9(...) github.com/wfusion/gofusion/http/construct.go 100.0% 3/3
router.rspSuccess(...) github.com/wfusion/gofusion/http/router.go 100.0% 3/3
@63:23(...) github.com/wfusion/gofusion/http/zerocopy.go 100.0% 2/2
ContentZeroCopy(...) github.com/wfusion/gofusion/http/zerocopy.go 100.0% 2/2
@636:4(...) github.com/wfusion/gofusion/http/router.go 100.0% 2/2
@637:4(...) github.com/wfusion/gofusion/http/router.go 100.0% 2/2
@140:8(...) github.com/wfusion/gofusion/http/construct.go 100.0% 2/2
@311:10(...) github.com/wfusion/gofusion/http/router.go 100.0% 2/2
StaticFileZeroCopy(...) github.com/wfusion/gofusion/http/zerocopy.go 100.0% 2/2
router.StaticFile(...) github.com/wfusion/gofusion/http/router.go 100.0% 2/2
@174:22(...) github.com/wfusion/gofusion/http/construct.go 100.0% 1/1
router.Group(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
@753:42(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
router.Closing(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
@243:9(...) github.com/wfusion/gofusion/http/construct.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/http/construct.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/http/construct.go 100.0% 1/1
router.Running(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/http/client.go 100.0% 1/1
asynqRedisConnOpt.MakeRedisClient(...) github.com/wfusion/gofusion/http/asynq.go 100.0% 1/1
router.Use(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
NewRequest(...) github.com/wfusion/gofusion/http/client.go 100.0% 1/1
router.ServeHTTP(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
@522:4(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
@521:4(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
Errcode.String(...) github.com/wfusion/gofusion/http/error.go 100.0% 1/1
@22:9(...) github.com/wfusion/gofusion/http/zerocopy.go 100.0% 1/1
@460:8(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
@37:9(...) github.com/wfusion/gofusion/http/client.go 100.0% 1/1
CName(...) github.com/wfusion/gofusion/http/client.go 100.0% 1/1
newRouter(...) github.com/wfusion/gofusion/http/router.go 100.0% 1/1
rspSuccess(...) github.com/wfusion/gofusion/http/response.go 90.9% 10/11
useClient(...) github.com/wfusion/gofusion/http/client.go 90.0% 9/10
addRouter(...) github.com/wfusion/gofusion/http/construct.go 88.5% 23/26
router.parseReqFromQuery(...) github.com/wfusion/gofusion/http/router.go 88.2% 15/17
router.shutdown(...) github.com/wfusion/gofusion/http/router.go 87.5% 7/8
New(...) github.com/wfusion/gofusion/http/client.go 87.1% 27/31
router.convert(...) github.com/wfusion/gofusion/http/router.go 86.7% 13/15
router.Start(...) github.com/wfusion/gofusion/http/router.go 85.7% 12/14
lookupFieldByMap(...) github.com/wfusion/gofusion/http/router.go 85.7% 6/7
Use(...) github.com/wfusion/gofusion/http/construct.go 85.7% 6/7
router.rspEmbed(...) github.com/wfusion/gofusion/http/router.go 82.4% 14/17
rspError(...) github.com/wfusion/gofusion/http/response.go 81.8% 9/11
@132:9(...) github.com/wfusion/gofusion/http/construct.go 80.0% 12/15
router.use(...) github.com/wfusion/gofusion/http/router.go 80.0% 4/5
router.parseReqFromBody(...) github.com/wfusion/gofusion/http/router.go 79.2% 19/24
@539:9(...) github.com/wfusion/gofusion/http/router.go 76.9% 20/26
initAsynq(...) github.com/wfusion/gofusion/http/asynq.go 75.0% 6/8
lookupFieldByValue(...) github.com/wfusion/gofusion/http/router.go 75.0% 3/4
router.convertMulti(...) github.com/wfusion/gofusion/http/router.go 71.4% 5/7
metricsCode(...) github.com/wfusion/gofusion/http/metrics.go 69.2% 9/13
traceHeaderMiddleware(...) github.com/wfusion/gofusion/http/client.go 66.7% 4/6
router.checkHandlerType(...) github.com/wfusion/gofusion/http/router.go 63.2% 12/19
ginZeroCopyWriter.ReadFrom(...) github.com/wfusion/gofusion/http/zerocopy.go 62.5% 10/16
parseRspError(...) github.com/wfusion/gofusion/http/router.go 62.5% 5/8
parseRspSuccess(...) github.com/wfusion/gofusion/http/router.go 58.3% 7/12
transformData(...) github.com/wfusion/gofusion/http/router.go 57.1% 4/7
@30:9(...) github.com/wfusion/gofusion/http/zerocopy.go 50.0% 4/8
embedResponse(...) github.com/wfusion/gofusion/http/response.go 50.0% 3/6
router.useIRouter(...) github.com/wfusion/gofusion/http/router.go 40.0% 2/5
applyClientOptions(...) github.com/wfusion/gofusion/http/client.go 23.1% 3/13
router.ListenAndServe(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/16
langs(...) github.com/wfusion/gofusion/http/response.go 0.0% 0/8
Localizable(...) github.com/wfusion/gofusion/http/i18n.go 0.0% 0/7
@101:17(...) github.com/wfusion/gofusion/http/construct.go 0.0% 0/5
@92:18(...) github.com/wfusion/gofusion/http/construct.go 0.0% 0/5
ErrCtx(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/4
Err(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/4
router.Handle(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
bizErr.Error(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/3
router.HEAD(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
router.PATCH(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
router.DELETE(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
@43:9(...) github.com/wfusion/gofusion/http/client.go 0.0% 0/3
@51:9(...) github.com/wfusion/gofusion/http/client.go 0.0% 0/3
router.PUT(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
router.OPTIONS(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/3
router.StaticFileFS(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/2
router.Static(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/2
router.StaticFS(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/2
@185:8(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/2
@71:8(...) github.com/wfusion/gofusion/http/zerocopy.go 0.0% 0/2
Langs(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
@129:22(...) github.com/wfusion/gofusion/http/construct.go 0.0% 0/1
@219:23(...) github.com/wfusion/gofusion/http/construct.go 0.0% 0/1
Errcode.Error(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
@37:9(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
@797:9(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
ParseFromQuery(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
@803:9(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
HandleBefore(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
@809:9(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
HandleAfter(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
@815:9(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
Param(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
RetryHook(...) github.com/wfusion/gofusion/http/client.go 0.0% 0/1
@43:9(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
ParseFromBody(...) github.com/wfusion/gofusion/http/router.go 0.0% 0/1
Msg(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
RetryCondition(...) github.com/wfusion/gofusion/http/client.go 0.0% 0/1
@49:9(...) github.com/wfusion/gofusion/http/error.go 0.0% 0/1
func lookupFieldByStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

695
func lookupFieldByStruct(rspStruct reflect.Value) (data any, page, count int, msg string) {
696
        var (
697
                routerResponsePageName = map[string]bool{
698
                        "page": true,
699
                        "Page": true,
700
                }
701
                routerResponseCountName = map[string]bool{
702
                        "count": true,
703
                        "Count": true,
704
                }
705
                routerResponseDataName = map[string]bool{
706
                        "data": true,
707
                        "Data": true,
708
                }
709
                routerResponseMsgName = map[string]bool{
710
                        "msg":     true,
711
                        "Msg":     true,
712
                        "message": true,
713
                        "Message": true,
714
                }
715
        )
716
717
        type lookupFunc func(v reflect.Value, keywords map[string]bool) (reflect.Value, bool)
718
        lookupFuncMap := map[reflect.Kind]lookupFunc{
719
                reflect.Map:    lookupFieldByMap,
720
                reflect.Struct: lookupFieldByValue,
721
        }
722
723
        rsp := utils.IndirectValue(rspStruct)
724
        lookup, ok := lookupFuncMap[rsp.Kind()]
725
        if !ok {
726
                data = rspStruct.Interface()
727
                return
728
        }
729
730
        // cannot parse response.Data, resolve all rspStruct as data
731
        if dataValue, ok := lookup(rsp, routerResponseDataName); ok {
732
                if dataValue.IsValid() {
733
                        data = transformData(reflect.ValueOf(valueInterface(dataValue, false)))
734
                }
735
        } else {
736
                data = rspStruct.Interface()
737
                return
738
        }
739
        if pageValue, ok := lookup(rsp, routerResponsePageName); ok && pageValue.IsValid() {
740
                page = cast.ToInt(pageValue.Int())
741
        }
742
        if countValue, ok := lookup(rsp, routerResponseCountName); ok && countValue.IsValid() {
743
                count = cast.ToInt(countValue.Int())
744
        }
745
        if msgValue, ok := lookup(rsp, routerResponseMsgName); ok && msgValue.IsValid() {
746
                msg = msgValue.String()
747
        }
748
749
        return
750
}
func addClient
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

189
func addClient(ctx context.Context, conf Conf, logger resty.Logger, opt *config.InitOption) func() {
190
        if _, ok := appClientCfgMap[opt.AppName]; !ok {
191
                defaultCfg := &cfg{
192
                        c:       clone.Clone(defaultClientConf),
193
                        appName: opt.AppName,
194
                        logger:  logger,
195
                }
196
                appClientCfgMap[opt.AppName] = map[string]*cfg{
197
                        "":        defaultCfg,
198
                        "default": defaultCfg,
199
                }
200
        }
201
        for name, cliConf := range conf.Clients {
202
                cliCfg := &cfg{
203
                        c:       cliConf,
204
                        appName: opt.AppName,
205
                        logger:  logger,
206
                }
207
                appClientCfgMap[opt.AppName][name] = cliCfg
208
                if name == config.DefaultInstanceKey {
209
                        appClientCfgMap[opt.AppName][""] = cliCfg
210
                }
211
212
                if opt.AppName == "" && name == config.DefaultInstanceKey {
213
                        Client = New(AppName(opt.AppName), CName(name))
214
                }
215
        }
216
217
        if opt.DI != nil {
218
                for name := range conf.Clients {
219
                        opt.DI.MustProvide(func() *resty.Client { return New(AppName(opt.AppName), CName(name)) }, di.Name(name))
220
                }
221
        }
222
223
        return func() {
224
                locker.Lock()
225
                defer locker.Unlock()
226
                if appClientMap != nil {
227
                        delete(appClientMap, opt.AppName)
228
                }
229
                if appClientCfgMap != nil {
230
                        delete(appClientCfgMap, opt.AppName)
231
                }
232
                if opt.AppName == "" {
233
                        Client = nil
234
                }
235
        }
236
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

41
func Construct(ctx context.Context, conf Conf, opts ...utils.OptionExtender) func() {
42
        opt := utils.ApplyOptions[config.InitOption](opts...)
43
        optU := utils.ApplyOptions[useOption](opts...)
44
        if opt.AppName == "" {
45
                opt.AppName = optU.appName
46
        }
47
48
        var logger resty.Logger
49
        if utils.IsStrNotBlank(conf.Logger) {
50
                logger = reflect.New(inspect.TypeOf(conf.Logger)).Interface().(resty.Logger)
51
                if custom, ok := logger.(customLogger); ok {
52
                        l := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
53
                        custom.Init(l, opt.AppName)
54
                }
55
        }
56
57
        exitRouterFn := addRouter(ctx, conf, logger, opt)
58
        exitI18nFn := addI18n(opt)
59
        exitClientFn := addClient(ctx, conf, logger, opt)
60
61
        // gracefully exit outside gofusion
62
        return func() {
63
                exitClientFn()
64
                exitRouterFn()
65
                exitI18nFn()
66
        }
67
}
func addI18n
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

156
func addI18n(opt *config.InitOption) func() {
157
        bundle := i18n.NewBundle[Errcode](i18n.DefaultLang(i18n.AppName(opt.AppName)))
158
        if I18n == nil {
159
                I18n = bundle
160
        }
161
        if i18ns == nil {
162
                i18ns = make(map[string]i18n.Localizable[Errcode])
163
        }
164
165
        i18ns[opt.AppName] = bundle
166
167
        // initialize http internal error
168
        bundle.AddMessages(errParam, map[language.Tag]*i18n.Message{
169
                language.English: {Other: "Invalid request parameters{{.err}}"},
170
                language.Chinese: {Other: "请求参数错误{{.err}}"},
171
        }, i18n.Var("err"))
172
173
        if opt.DI != nil {
174
                opt.DI.MustProvide(func() i18n.Localizable[Errcode] { return bundle })
175
        }
176
177
        return func() {
178
                locker.Lock()
179
                defer locker.Unlock()
180
                if i18ns != nil {
181
                        delete(i18ns, opt.AppName)
182
                }
183
                if opt.AppName == "" {
184
                        I18n = nil
185
                }
186
        }
187
}
func @223:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

223
func() {
224
                locker.Lock()
225
                defer locker.Unlock()
226
                if appClientMap != nil {
227
                        delete(appClientMap, opt.AppName)
228
                }
229
                if appClientCfgMap != nil {
230
                        delete(appClientCfgMap, opt.AppName)
231
                }
232
                if opt.AppName == "" {
233
                        Client = nil
234
                }
235
        }
func @177:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

177
func() {
178
                locker.Lock()
179
                defer locker.Unlock()
180
                if i18ns != nil {
181
                        delete(i18ns, opt.AppName)
182
                }
183
                if opt.AppName == "" {
184
                        I18n = nil
185
                }
186
        }
func router.checkParamType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

431
func (r *router) checkParamType(typ reflect.Type, supportType map[reflect.Kind]struct{}) bool {
432
        if typ.Kind() == reflect.Ptr {
433
                typ = typ.Elem()
434
        }
435
        _, ok := supportType[typ.Kind()]
436
        return ok
437
}
func @498:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

498
func() {
499
                for ptrDepth > 0 {
500
                        dst = dst.Addr()
501
                        ptrDepth--
502
                }
503
        }
func router.Any
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

100
func (r *router) Any(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
101
        opt := utils.ApplyOptions[routerOption](opts...)
102
        r.use().Any(uri, r.convertMulti("Any", uri, fn, opt)...)
103
        return r
104
}
func router.rspError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

592
func (r *router) rspError(c *gin.Context, rspVals []reflect.Value, err error) {
593
        code, data, page, count, msg := parseRspError(rspVals, err)
594
        rspError(c, r.appName, code, data, page, count, msg)
595
596
        go metricsCode(r.ctx, r.appName, c.Request.URL.Path, c.Request.Method, cast.ToInt(code),
597
                c.Writer.Status(), c.Writer.Size(), c.Request.ContentLength)
598
}
func router.wrapHandlerFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

536
func (r *router) wrapHandlerFunc(handler routerHandler, reqParse routerRequestParser) gin.HandlerFunc {
537
        typ := reflect.TypeOf(handler)
538
        numOut := typ.NumOut()
539
        return func(c *gin.Context) {
540
                var (
541
                        err     error
542
                        reqVal  reflect.Value
543
                        rspVals []reflect.Value
544
                )
545
546
                // deal with request & call handler
547
                if reqParse == nil {
548
                        rspVals = reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c)})
549
                } else if reqVal, err = reqParse(c, typ.In(1)); err == nil {
550
                        rspVals = reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c), reqVal})
551
                } else {
552
                        switch e := err.(type) {
553
                        case *json.UnmarshalTypeError:
554
                                msg := fmt.Sprintf(": %s field type should be %s", e.Value, e.Type.String())
555
                                r.rspError(c, nil, Err(c, errParam, Param(map[string]any{"err": msg})))
556
                        default:
557
                                r.rspError(c, nil, Err(c, errParam,
558
                                        Param(map[string]any{"err": fmt.Sprintf(": %s", err.Error())})))
559
                        }
560
                        c.Next()
561
                        return
562
                }
563
564
                // deal with response
565
                errVal := rspVals[numOut-1]
566
                if !errVal.IsNil() {
567
                        err = errVal.Interface().(error)
568
                }
569
                rspVals = rspVals[:numOut-1]
570
571
                var rspType reflect.Type
572
                isEmbed, isResponse := false, false
573
                if len(rspVals) > 0 {
574
                        rspType = utils.IndirectType(rspVals[0].Type())
575
                        isEmbed = utils.EmbedsType(rspType, embedType)
576
                        isResponse = utils.EmbedsType(rspType, responseType)
577
                }
578
579
                switch {
580
                case isEmbed, isResponse:
581
                        r.rspEmbed(c, rspVals[0], rspType, err) // directly json marshal embed response
582
                case err != nil:
583
                        r.rspError(c, rspVals, err) // business error
584
                default:
585
                        r.rspSuccess(c, rspVals) // success with response
586
                }
587
588
                c.Next()
589
        }
590
}
func router.Config
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

217
func (r *router) Config() OutputConf {
218
        cfg := new(Conf)
219
        _ = config.Use(r.appName).LoadComponentConfig(config.ComponentHttp, cfg)
220
221
        return OutputConf{
222
                Port:         cfg.Port,
223
                TLS:          cfg.TLS,
224
                Cert:         cfg.Cert,
225
                Key:          cfg.Key,
226
                NextProtos:   cfg.NextProtos,
227
                SuccessCode:  cfg.SuccessCode,
228
                ReadTimeout:  utils.Must(time.ParseDuration(cfg.ReadTimeout)),
229
                WriteTimeout: utils.Must(time.ParseDuration(cfg.WriteTimeout)),
230
                AsynqConf:    clone.Slowly(cfg.Asynq),
231
        }
232
}
func router.POST
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

110
func (r *router) POST(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
111
        opt := utils.ApplyOptions[routerOption](opts...)
112
        r.use().POST(uri, r.convertMulti(http.MethodPost, uri, fn, opt)...)
113
        return r
114
}
func router.GET
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

105
func (r *router) GET(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
106
        opt := utils.ApplyOptions[routerOption](opts...)
107
        r.use().GET(uri, r.convertMulti(http.MethodGet, uri, fn, opt)...)
108
        return r
109
}
func @445:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

445
func() {
446
                for ptrDepth > 0 {
447
                        dst = dst.Addr()
448
                        ptrDepth--
449
                }
450
        }
func @62:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

62
func() {
63
                exitClientFn()
64
                exitRouterFn()
65
                exitI18nFn()
66
        }
func router.rspSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

600
func (r *router) rspSuccess(c *gin.Context, rspVals []reflect.Value) {
601
        data, page, count, msg := parseRspSuccess(rspVals)
602
        rspSuccess(c, r.successCode, data, page, count, msg)
603
604
        go metricsCode(r.ctx, r.appName, c.Request.URL.Path, c.Request.Method, r.successCode,
605
                c.Writer.Status(), c.Writer.Size(), c.Request.ContentLength)
606
}
func @63:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

63
func() (err error) { conn, _, err = z.ResponseWriter.Hijack(); return }
func ContentZeroCopy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

28
func ContentZeroCopy(fn getContentFn, opts ...utils.OptionExtender) func(c *gin.Context) {
29
        opt := utils.ApplyOptions[useOption](opts...)
30
        return func(c *gin.Context) {
31
                name, modTime, content, err := fn(c)
32
                if err != nil {
33
                        code, data, page, count, msg := parseRspError(nil, err)
34
                        rspError(c, opt.appName, code, data, page, count, msg)
35
                        c.Abort()
36
                        return
37
                }
38
                defer utils.CloseAnyway(content)
39
                http.ServeContent(&ginZeroCopyWriter{ResponseWriter: c.Writer, ctx: c}, c.Request, name, modTime, content)
40
        }
41
}
func @636:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

636
func() (ok bool) { code, ok = rspData["code"]; return ok }
func @637:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

637
func() (ok bool) { code, ok = rspData["Code"]; return ok }
func @140:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

140
func() { defer wg.Done(); <-router.Closing() }
func @311:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

311
func(c *gin.Context) {
312
                        reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c)})
313
                        c.Next()
314
                }
func StaticFileZeroCopy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

20
func StaticFileZeroCopy(filename string) func(c *gin.Context) {
21
        filename = path.Clean(filename)
22
        return func(c *gin.Context) {
23
                http.ServeFile(&ginZeroCopyWriter{ResponseWriter: c.Writer, ctx: c}, c.Request, filename)
24
        }
25
}
func router.StaticFile
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

154
func (r *router) StaticFile(uri, file string) IRouter { r.use().StaticFile(uri, file); return r }
func @174:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

174
func() i18n.Localizable[Errcode] { return bundle }
func router.Group
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

140
func (r *router) Group(relativePath string, handlers ...gin.HandlerFunc) IRouter {
141
        return &router{
142
                IRouter:     r.IRouter,
143
                open:        r.open,
144
                close:       r.close,
145
                ctx:         r.ctx,
146
                appName:     r.appName,
147
                successCode: r.successCode,
148
                routes:      r.routes,
149
                group:       r.useIRouter().Group(relativePath, handlers...),
150
                ptr:         dispatchGroup,
151
        }
152
}
func @753:42
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

753
func(s string) bool { return keywords[s] }
func router.Closing
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

234
func (r *router) Closing() <-chan struct{} { return r.close }
func @243:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

243
func(o *useOption) {
244
                o.appName = name
245
        }
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

242
func AppName(name string) utils.OptionFunc[useOption] {
243
        return func(o *useOption) {
244
                o.appName = name
245
        }
246
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

260
func init() {
261
        config.AddComponent(config.ComponentHttp, Construct)
262
}
func router.Running
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

233
func (r *router) Running() <-chan struct{} { return r.open }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

186
func init() {
187
        _ = utils.ParseTag(defaultClientConf,
188
                utils.ParseTagName("default"),
189
                utils.ParseTagUnmarshalType(utils.UnmarshalTypeYaml))
190
}
func asynqRedisConnOpt.MakeRedisClient
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/asynq.go:

42
func (a *asynqRedisConnOpt) MakeRedisClient() any { return a.UniversalClient }
func router.Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

81
func (r *router) Use(middlewares ...gin.HandlerFunc) IRouter {
82
        return &router{
83
                IRouter:     r.IRouter,
84
                open:        r.open,
85
                close:       r.close,
86
                ctx:         r.ctx,
87
                appName:     r.appName,
88
                successCode: r.successCode,
89
                routes:      r.use().Use(middlewares...),
90
                group:       r.group,
91
                ptr:         dispatchRoutes,
92
        }
93
}
func NewRequest
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

130
func NewRequest(ctx context.Context, opts ...utils.OptionExtender) *resty.Request {
131
        return New(opts...).R().SetContext(ctx)
132
}
func router.ServeHTTP
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

165
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
166
        r.IRouter.(*gin.Engine).ServeHTTP(w, req)
167
}
func @522:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

522
func() error { return parser.MapFormByTag(dst.Addr().Interface(), c.Request.URL.Query(), "json") }
func @521:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

521
func() error { return parser.MapFormByTag(dst.Addr().Interface(), m, "json") }
func Errcode.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

23
func (e Errcode) String() (r string) {
24
        return strconv.Itoa(int(e))
25
}
func @22:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

22
func(c *gin.Context) {
23
                http.ServeFile(&ginZeroCopyWriter{ResponseWriter: c.Writer, ctx: c}, c.Request, filename)
24
        }
func @460:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

460
func() { c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) }
func @37:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

37
func(o *clientOption) {
38
                o.name = name
39
        }
func CName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

36
func CName(name string) utils.OptionFunc[clientOption] {
37
        return func(o *clientOption) {
38
                o.name = name
39
        }
40
}
func newRouter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

70
func newRouter(ctx context.Context, r gin.IRouter, appName string, successCode int) IRouter {
71
        return &router{
72
                IRouter:     r,
73
                ctx:         ctx,
74
                open:        make(chan struct{}),
75
                close:       make(chan struct{}),
76
                appName:     appName,
77
                successCode: successCode,
78
        }
79
}
func rspSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/response.go:

38
func rspSuccess(c *gin.Context, code int, data any, page, count int, msg string) {
39
        status := c.Writer.Status()
40
        if status <= 0 {
41
                status = http.StatusOK
42
        }
43
        if msg == "" {
44
                msg = "ok"
45
        }
46
        var (
47
                pagePtr  *int
48
                countPtr *int
49
        )
50
        if page > 0 {
51
                pagePtr = utils.AnyPtr(page)
52
        }
53
        if count >= 0 {
54
                countPtr = utils.AnyPtr(count)
55
        }
56
57
        c.PureJSON(status, &Response{
58
                Code:    code,
59
                Message: msg,
60
                Data:    data,
61
                Page:    pagePtr,
62
                Count:   countPtr,
63
                TraceID: c.GetString(fusCtx.KeyTraceID),
64
        })
65
}
func useClient
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

171
func useClient(opts ...utils.OptionExtender) (cli *resty.Client) {
172
        locker.RLock()
173
        defer locker.RUnlock()
174
175
        opt := utils.ApplyOptions[clientOption](opts...)
176
        opt.appName = utils.ApplyOptions[useOption](opts...).appName
177
        locker.RLock()
178
        defer locker.RUnlock()
179
        appClients, ok := appClientMap[opt.appName]
180
        if !ok {
181
                return
182
        }
183
        return appClients[opt.name]
184
}
func addRouter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

69
func addRouter(ctx context.Context, conf Conf, logger resty.Logger, opt *config.InitOption) func() {
70
        engine := gin.New()
71
        engine.Use(
72
                gin.Recovery(),
73
                middleware.Gateway,
74
                middleware.Trace(),
75
                middleware.Logging(ctx, opt.AppName, logger),
76
                middleware.Cors(),
77
                middleware.XSS(conf.XSSWhiteURLList),
78
                middleware.Recover(opt.AppName, logger),
79
        )
80
        if config.Use(opt.AppName).Debug() {
81
                gin.SetMode(gin.DebugMode)
82
        } else {
83
                gin.SetMode(gin.ReleaseMode)
84
        }
85
        if !conf.ColorfulConsole {
86
                gin.DisableConsoleColor()
87
        } else {
88
                gin.ForceConsoleColor()
89
        }
90
91
        tag := i18n.DefaultLang(i18n.AppName(opt.AppName))
92
        engine.NoMethod(func(c *gin.Context) {
93
                c.Status(http.StatusMethodNotAllowed)
94
                msg := fmt.Sprintf("找不到该方法, Method: %s", c.Request.Method)
95
                if tag != language.Chinese {
96
                        msg = fmt.Sprintf("Cannot find method: %s", c.Request.Method)
97
                }
98
99
                rspError(c, opt.AppName, -1, nil, 0, 0, msg)
100
        })
101
        engine.NoRoute(func(c *gin.Context) {
102
                c.Status(http.StatusNotFound)
103
                msg := fmt.Sprintf("找不到该内容, URL: %s", c.Request.URL.String())
104
                if tag != language.Chinese {
105
                        msg = fmt.Sprintf("Cannot find URL content: %s", c.Request.URL.String())
106
                }
107
                rspError(c, opt.AppName, -1, nil, 0, 0, msg)
108
        })
109
110
        if conf.Pprof {
111
                pprof.Register(engine)
112
        }
113
        instance := newRouter(ctx, engine, opt.AppName, conf.SuccessCode)
114
115
        locker.Lock()
116
        defer locker.Unlock()
117
        if len(conf.Asynq) > 0 {
118
                initAsynq(ctx, opt.AppName, instance, conf.Asynq)
119
        }
120
        if _, ok := routers[opt.AppName]; ok {
121
                panic(errors.Errorf("duplicated http name: %s", opt.AppName))
122
        }
123
        routers[opt.AppName] = instance
124
        if opt.AppName == "" {
125
                Router = instance
126
        }
127
128
        if opt.DI != nil {
129
                opt.DI.MustProvide(func() IRouter { return Use(AppName(opt.AppName)) })
130
        }
131
132
        return func() {
133
                locker.Lock()
134
                defer locker.Unlock()
135
                if routers != nil {
136
                        if router, ok := routers[opt.AppName]; ok {
137
                                router.shutdown()
138
                                wg := new(sync.WaitGroup)
139
                                wg.Add(1)
140
                                go func() { defer wg.Done(); <-router.Closing() }()
141
                                if utils.Timeout(15*time.Second, utils.TimeoutWg(wg)) {
142
                                        pid := syscall.Getpid()
143
                                        app := config.Use(opt.AppName).AppName()
144
                                        log.Printf("%v [Gofusion] %s %s close http server timeout", pid, app, config.ComponentHttp)
145
                                }
146
                        }
147
148
                        delete(routers, opt.AppName)
149
                }
150
                if opt.AppName == "" {
151
                        Router = nil
152
                }
153
        }
154
}
func router.parseReqFromQuery
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

492
func (r *router) parseReqFromQuery(c *gin.Context, typ reflect.Type) (dst reflect.Value, err error) {
493
        ptrDepth := 0
494
        for typ.Kind() == reflect.Ptr {
495
                typ = typ.Elem()
496
                ptrDepth++
497
        }
498
        defer func() {
499
                for ptrDepth > 0 {
500
                        dst = dst.Addr()
501
                        ptrDepth--
502
                }
503
        }()
504
505
        dst = reflect.Indirect(reflect.New(typ))
506
        if err = c.ShouldBindUri(dst.Addr().Interface()); err != nil &&
507
                !(errors.Is(err, binding.ErrConvertToMapString) || (errors.Is(err, binding.ErrConvertMapStringSlice))) {
508
                return
509
        }
510
        if err = c.ShouldBindQuery(dst.Addr().Interface()); err != nil &&
511
                !(errors.Is(err, binding.ErrConvertToMapString) || (errors.Is(err, binding.ErrConvertMapStringSlice))) {
512
                return
513
        }
514
        // support query with json tag
515
        if dst.IsZero() {
516
                m := make(map[string][]string)
517
                for _, v := range c.Params {
518
                        m[v.Key] = []string{v.Value}
519
                }
520
                err = utils.CheckIfAny(
521
                        func() error { return parser.MapFormByTag(dst.Addr().Interface(), m, "json") },
522
                        func() error { return parser.MapFormByTag(dst.Addr().Interface(), c.Request.URL.Query(), "json") },
523
                )
524
        }
525
526
        // parse default tag
527
        err = utils.ParseTag(
528
                dst.Addr().Interface(),
529
                utils.ParseTagName("default"),
530
                utils.ParseTagUnmarshalType(utils.UnmarshalTypeYaml),
531
        )
532
533
        return
534
}
func router.shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

236
func (r *router) shutdown() {
237
        if r.close != nil {
238
                if _, ok := utils.IsChannelClosed(r.close); ok {
239
                        return
240
                }
241
        }
242
        if r.shutdownFunc != nil {
243
                r.shutdownFunc()
244
        }
245
        if r.close != nil {
246
                close(r.close)
247
        }
248
249
        r.open = make(chan struct{})
250
}
func New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

58
func New(opts ...utils.OptionExtender) *resty.Client {
59
        opt := utils.ApplyOptions[clientOption](opts...)
60
        opt.appName = utils.ApplyOptions[useOption](opts...).appName
61
62
        cli := useClient(opts...)
63
        if cli != nil {
64
                return applyClientOptions(cli, opt)
65
        }
66
67
        locker.Lock()
68
        defer locker.Unlock()
69
70
        c := resty.New().
71
                OnBeforeRequest(traceHeaderMiddleware).
72
                SetTransport(http.DefaultTransport).
73
                SetJSONMarshaler(json.Marshal).
74
                SetJSONUnmarshaler(json.Unmarshal).
75
                SetDebug(true)
76
77
        cfg, ok := appClientCfgMap[opt.appName][opt.name]
78
        if !ok {
79
                cfg = appClientCfgMap[opt.appName][config.DefaultInstanceKey]
80
        }
81
82
        if cfg.logger != nil {
83
                c.SetLogger(cfg.logger)
84
        }
85
86
        if cliCfg := cfg.c; cliCfg == nil || !cliCfg.Mock {
87
                c.EnableTrace()
88
        } else {
89
                c.SetTimeout(utils.Must(time.ParseDuration(cliCfg.Timeout)))
90
                c.SetRetryCount(cliCfg.RetryCount)
91
                c.SetRetryWaitTime(utils.Must(time.ParseDuration(cliCfg.RetryWaitTime)))
92
                c.SetRetryMaxWaitTime(utils.Must(time.ParseDuration(cliCfg.RetryMaxWaitTime)))
93
                for _, funcName := range cliCfg.RetryConditionFuncs {
94
                        c.AddRetryCondition(*(*resty.RetryConditionFunc)(inspect.FuncOf(funcName)))
95
                }
96
                for _, hookName := range cliCfg.RetryHooks {
97
                        c.AddRetryHook(*(*resty.OnRetryFunc)(inspect.FuncOf(hookName)))
98
                }
99
100
                dialer := &net.Dialer{
101
                        Timeout:   utils.Must(time.ParseDuration(cliCfg.DialTimeout)),
102
                        KeepAlive: utils.Must(time.ParseDuration(cliCfg.DialKeepaliveTime)),
103
                }
104
105
                c.SetTransport(&http.Transport{
106
                        Proxy:                 http.ProxyFromEnvironment,
107
                        DialContext:           dialer.DialContext,
108
                        ForceAttemptHTTP2:     cliCfg.ForceAttemptHTTP2,
109
                        DisableCompression:    cliCfg.DisableCompression,
110
                        IdleConnTimeout:       utils.Must(time.ParseDuration(cliCfg.IdleConnTimeout)),
111
                        TLSHandshakeTimeout:   utils.Must(time.ParseDuration(cliCfg.TLSHandshakeTimeout)),
112
                        ExpectContinueTimeout: utils.Must(time.ParseDuration(cliCfg.TLSHandshakeTimeout)),
113
                        MaxIdleConns:          cliCfg.MaxIdleConns,
114
                        MaxIdleConnsPerHost:   cliCfg.MaxIdleConnsPerHost,
115
                        MaxConnsPerHost:       cliCfg.MaxConnsPerHost,
116
                })
117
118
                if cliCfg.Mock {
119
                        httpmock.ActivateNonDefault(c.GetClient())
120
                }
121
        }
122
123
        if _, ok := appClientMap[opt.appName]; !ok {
124
                appClientMap[opt.appName] = make(map[string]*resty.Client)
125
        }
126
        appClientMap[opt.appName][opt.name] = c
127
        return applyClientOptions(c, opt)
128
}
func router.convert
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

302
func (r *router) convert(method, uri string, handler routerHandler, opt *routerOption) gin.HandlerFunc {
303
        // check IRouter handler type
304
        typ := reflect.TypeOf(handler)
305
        if err := r.checkHandlerType(method, uri, typ); err != nil {
306
                panic(err)
307
        }
308
309
        // return raw gin handler
310
        if typ.NumIn() == 1 && typ.NumOut() == 0 {
311
                return func(c *gin.Context) {
312
                        reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c)})
313
                        c.Next()
314
                }
315
        }
316
317
        // parse request&response
318
        if typ.NumIn() == 1 {
319
                return r.wrapHandlerFunc(handler, nil)
320
        }
321
322
        parseMap := map[parseFrom]routerRequestParser{
323
                parseFromBody:  r.parseReqFromBody,
324
                parseFromQuery: r.parseReqFromQuery,
325
        }
326
327
        var reqParse routerRequestParser
328
        if p, ok := parseMap[opt.parseFrom]; ok {
329
                reqParse = p
330
        } else if methodWithBody[method] {
331
                reqParse = r.parseReqFromBody
332
        } else {
333
                reqParse = r.parseReqFromQuery
334
        }
335
336
        return r.wrapHandlerFunc(handler, reqParse)
337
}
func router.Start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

196
func (r *router) Start() {
197
        if _, ok := utils.IsChannelClosed(r.open); ok {
198
                return
199
        }
200
        conf := r.Config()
201
        gracefully.DefaultReadTimeOut = conf.ReadTimeout
202
        gracefully.DefaultWriteTimeOut = conf.WriteTimeout
203
        gracefully.DefaultMaxHeaderBytes = 1 << 20 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
204
205
        port := fmt.Sprintf(":%v", conf.Port)
206
        srv := gracefully.NewServer(r.appName, r.IRouter.(*gin.Engine), port, conf.NextProtos)
207
        r.shutdownFunc = srv.Shutdown
208
        if conf.TLS {
209
                routine.Go(srv.ListenAndServeTLS, routine.Args(conf.Cert, conf.Key), routine.AppName(r.appName))
210
        } else {
211
                routine.Go(srv.ListenAndServe, routine.AppName(r.appName))
212
        }
213
214
        r.close = make(chan struct{})
215
        close(r.open)
216
}
func lookupFieldByMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

760
func lookupFieldByMap(v reflect.Value, keywords map[string]bool) (reflect.Value, bool) {
761
        vMap, ok := v.Interface().(map[string]any)
762
        if !ok {
763
                return reflect.Value{}, false
764
        }
765
766
        for key := range keywords {
767
                if vv, ok := vMap[key]; ok {
768
                        return reflect.ValueOf(vv), true
769
                }
770
        }
771
        return reflect.Value{}, false
772
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

248
func Use(opts ...utils.OptionExtender) IRouter {
249
        opt := utils.ApplyOptions[useOption](opts...)
250
        locker.RLock()
251
        defer locker.RUnlock()
252
253
        router, ok := routers[opt.appName]
254
        if !ok {
255
                panic(errors.Errorf("router not found"))
256
        }
257
        return router
258
}
func router.rspEmbed
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

608
func (r *router) rspEmbed(c *gin.Context, rspVal reflect.Value, rspType reflect.Type, err error) {
609
        var data any
610
        if rspVal.IsValid() {
611
                data = rspVal.Interface()
612
        } else {
613
                data = reflect.New(rspType).Interface()
614
        }
615
616
        embedResponse(c, data, err)
617
618
        switch rsp := data.(type) {
619
        case Response:
620
                go metricsCode(r.ctx, r.appName, c.Request.URL.Path, c.Request.Method, rsp.Code,
621
                        c.Writer.Status(), c.Writer.Size(), c.Request.ContentLength)
622
        case *Response:
623
                go metricsCode(r.ctx, r.appName, c.Request.URL.Path, c.Request.Method, rsp.Code,
624
                        c.Writer.Status(), c.Writer.Size(), c.Request.ContentLength)
625
        default:
626
                rspData := make(map[string]any)
627
                dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
628
                        Result:  &rspData,
629
                        TagName: "json",
630
                })
631
                if err == nil && dec != nil {
632
                        _ = dec.Decode(data)
633
                }
634
                var code any
635
                utils.IfAny(
636
                        func() (ok bool) { code, ok = rspData["code"]; return ok },
637
                        func() (ok bool) { code, ok = rspData["Code"]; return ok },
638
                )
639
                if code == nil {
640
                        code = -2
641
                }
642
                go metricsCode(r.ctx, r.appName, c.Request.URL.Path, c.Request.Method, cast.ToInt(code),
643
                        c.Writer.Status(), c.Writer.Size(), c.Request.ContentLength)
644
        }
645
646
}
func rspError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/response.go:

67
func rspError[T constraint.Integer](c *gin.Context, appName string, code T, data any, page, count int, msg string) {
68
        status := c.Writer.Status()
69
        if status <= 0 {
70
                status = http.StatusBadRequest
71
        }
72
73
        if msg == "" {
74
                msg = Localizable(AppName(appName)).Localize(Errcode(code), i18n.Langs(langs(c)))
75
        }
76
        var (
77
                pagePtr  *int
78
                countPtr *int
79
        )
80
        if page > 0 {
81
                pagePtr = utils.AnyPtr(page)
82
        }
83
        if count >= 0 {
84
                countPtr = utils.AnyPtr(count)
85
        }
86
87
        c.PureJSON(status, &Response{
88
                Code:    cast.ToInt(code),
89
                Message: msg,
90
                Data:    data,
91
                Page:    pagePtr,
92
                Count:   countPtr,
93
                TraceID: c.GetString(fusCtx.KeyTraceID),
94
        })
95
}
func @132:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

132
func() {
133
                locker.Lock()
134
                defer locker.Unlock()
135
                if routers != nil {
136
                        if router, ok := routers[opt.AppName]; ok {
137
                                router.shutdown()
138
                                wg := new(sync.WaitGroup)
139
                                wg.Add(1)
140
                                go func() { defer wg.Done(); <-router.Closing() }()
141
                                if utils.Timeout(15*time.Second, utils.TimeoutWg(wg)) {
142
                                        pid := syscall.Getpid()
143
                                        app := config.Use(opt.AppName).AppName()
144
                                        log.Printf("%v [Gofusion] %s %s close http server timeout", pid, app, config.ComponentHttp)
145
                                }
146
                        }
147
148
                        delete(routers, opt.AppName)
149
                }
150
                if opt.AppName == "" {
151
                        Router = nil
152
                }
153
        }
func router.use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

252
func (r *router) use() gin.IRoutes {
253
        switch r.ptr {
254
        case dispatchIRouter:
255
                return r.IRouter
256
        case dispatchGroup:
257
                return r.group
258
        case dispatchRoutes:
259
                return r.routes
260
        default:
261
                return r.IRouter
262
        }
263
}
func router.parseReqFromBody
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

439
func (r *router) parseReqFromBody(c *gin.Context, typ reflect.Type) (dst reflect.Value, err error) {
440
        ptrDepth := 0
441
        for typ.Kind() == reflect.Ptr {
442
                typ = typ.Elem()
443
                ptrDepth++
444
        }
445
        defer func() {
446
                for ptrDepth > 0 {
447
                        dst = dst.Addr()
448
                        ptrDepth--
449
                }
450
        }()
451
452
        bodyBytes, _ := io.ReadAll(c.Request.Body)
453
        c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
454
455
        dst = reflect.Indirect(reflect.New(typ))
456
        if err = c.ShouldBind(dst.Addr().Interface()); err != nil &&
457
                !(errors.Is(err, binding.ErrConvertToMapString) || (errors.Is(err, binding.ErrConvertMapStringSlice))) {
458
                return
459
        }
460
        defer func() { c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) }()
461
462
        if dst.IsZero() {
463
                var (
464
                        p           parser.Parser
465
                        param       map[string]string
466
                        contentType string
467
                )
468
                if contentType, param, err = mime.ParseMediaType(c.GetHeader("Content-Type")); err != nil {
469
                        return
470
                }
471
                if p, err = parser.GetByContentType(contentType); err != nil {
472
                        return
473
                }
474
                if err = p.PreParse(param); err != nil {
475
                        return
476
                }
477
                c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
478
                if err = p.Parse(c.Request.Body, dst); err != nil {
479
                        return
480
                }
481
        }
482
483
        err = utils.ParseTag(
484
                dst.Addr().Interface(),
485
                utils.ParseTagName("default"),
486
                utils.ParseTagUnmarshalType(utils.UnmarshalTypeYaml),
487
        )
488
489
        return
490
}
func @539:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

539
func(c *gin.Context) {
540
                var (
541
                        err     error
542
                        reqVal  reflect.Value
543
                        rspVals []reflect.Value
544
                )
545
546
                // deal with request & call handler
547
                if reqParse == nil {
548
                        rspVals = reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c)})
549
                } else if reqVal, err = reqParse(c, typ.In(1)); err == nil {
550
                        rspVals = reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(c), reqVal})
551
                } else {
552
                        switch e := err.(type) {
553
                        case *json.UnmarshalTypeError:
554
                                msg := fmt.Sprintf(": %s field type should be %s", e.Value, e.Type.String())
555
                                r.rspError(c, nil, Err(c, errParam, Param(map[string]any{"err": msg})))
556
                        default:
557
                                r.rspError(c, nil, Err(c, errParam,
558
                                        Param(map[string]any{"err": fmt.Sprintf(": %s", err.Error())})))
559
                        }
560
                        c.Next()
561
                        return
562
                }
563
564
                // deal with response
565
                errVal := rspVals[numOut-1]
566
                if !errVal.IsNil() {
567
                        err = errVal.Interface().(error)
568
                }
569
                rspVals = rspVals[:numOut-1]
570
571
                var rspType reflect.Type
572
                isEmbed, isResponse := false, false
573
                if len(rspVals) > 0 {
574
                        rspType = utils.IndirectType(rspVals[0].Type())
575
                        isEmbed = utils.EmbedsType(rspType, embedType)
576
                        isResponse = utils.EmbedsType(rspType, responseType)
577
                }
578
579
                switch {
580
                case isEmbed, isResponse:
581
                        r.rspEmbed(c, rspVals[0], rspType, err) // directly json marshal embed response
582
                case err != nil:
583
                        r.rspError(c, rspVals, err) // business error
584
                default:
585
                        r.rspSuccess(c, rspVals) // success with response
586
                }
587
588
                c.Next()
589
        }
func initAsynq
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/asynq.go:

15
func initAsynq(ctx context.Context, appName string, r IRouter, confs []asynqConf) {
16
        if len(confs) == 0 || r == nil {
17
                return
18
        }
19
20
        for _, conf := range confs {
21
                switch conf.InstanceType {
22
                case instanceTypeRedis:
23
                default:
24
                        panic(errors.Errorf("unknown asynq instance type: %+v", conf.InstanceType))
25
                }
26
                connOpt := &asynqRedisConnOpt{UniversalClient: redis.Use(ctx, conf.Instance, redis.AppName(appName))}
27
                h := asynqmon.New(asynqmon.Options{
28
                        RootPath:          conf.Path,
29
                        RedisConnOpt:      connOpt,
30
                        PayloadFormatter:  nil,
31
                        ResultFormatter:   nil,
32
                        PrometheusAddress: conf.PrometheusAddress,
33
                        ReadOnly:          conf.Readonly,
34
                })
35
36
                r.Any(h.RootPath()+"/*any", gin.WrapH(h))
37
        }
38
}
func lookupFieldByValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

752
func lookupFieldByValue(v reflect.Value, keywords map[string]bool) (reflect.Value, bool) {
753
        f := reflect.Indirect(v.FieldByNameFunc(func(s string) bool { return keywords[s] }))
754
        if !f.IsValid() || f.IsZero() {
755
                return reflect.Value{}, false
756
        }
757
        return reflect.Indirect(f), true
758
}
func router.convertMulti
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

339
func (r *router) convertMulti(method, uri string, hdr routerHandler, opt *routerOption) (result gin.HandlersChain) {
340
        result = make(gin.HandlersChain, 0, len(opt.beforeHandlers)+len(opt.aftersHandlers)+1)
341
        for _, hdr := range opt.beforeHandlers {
342
                result = append(result, r.convert(method, uri, hdr, opt))
343
        }
344
        result = append(result, r.convert(method, uri, hdr, opt))
345
        for _, hdr := range opt.aftersHandlers {
346
                result = append(result, r.convert(method, uri, hdr, opt))
347
        }
348
        return
349
}
func metricsCode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/metrics.go:

17
func metricsCode(ctx context.Context, appName, path, method string, code, status, rspSize int, reqSize int64) {
18
        select {
19
        case <-ctx.Done():
20
                return
21
        default:
22
23
        }
24
25
        // skip health check logging
26
        if path == "/health" && method == http.MethodGet {
27
                return
28
        }
29
30
        app := config.Use(appName).AppName()
31
        labels := []metrics.Label{
32
                {Key: "path", Value: path},
33
                {Key: "method", Value: method},
34
                {Key: "code", Value: cast.ToString(code)},
35
                {Key: "status", Value: cast.ToString(status)},
36
                {Key: "req_size", Value: cast.ToString(reqSize)},
37
                {Key: "rsp_size", Value: cast.ToString(rspSize)},
38
        }
39
        totalKey := append([]string{app}, metricsCodeTotalKey...)
40
        for _, m := range metrics.Internal(metrics.AppName(appName)) {
41
                select {
42
                case <-ctx.Done():
43
                        return
44
                default:
45
                        if m.IsEnableServiceLabel() {
46
                                m.IncrCounter(ctx, totalKey, 1, metrics.Labels(labels))
47
                        } else {
48
                                m.IncrCounter(ctx, metricsCodeTotalKey, 1, metrics.Labels(labels))
49
                        }
50
                }
51
        }
52
}
func traceHeaderMiddleware
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

134
func traceHeaderMiddleware(cli *resty.Client, req *resty.Request) (err error) {
135
        ctx := req.Context()
136
        if userID := fusCtx.GetUserID(ctx); utils.IsStrNotBlank(userID) {
137
                req.SetHeader("User-ID", userID)
138
        }
139
        if traceID := fusCtx.GetTraceID(ctx); utils.IsStrNotBlank(traceID) {
140
                req.SetHeader("Trace-ID", traceID)
141
        }
142
        return
143
}
func router.checkHandlerType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

351
func (r *router) checkHandlerType(method, uri string, typ reflect.Type) (err error) {
352
        if typ.Kind() != reflect.Func {
353
                return errors.Errorf("router handler should be a function [method[%s] uri[%s]]", method, uri)
354
        }
355
356
        // check in
357
        if typ.NumIn() < 1 {
358
                return errors.Errorf("router handler should have at least 1 parameter in "+
359
                        "[method[%s] uri[%s]]", method, uri)
360
        }
361
        if typ.NumIn() > 2 {
362
                return errors.Errorf("router handler should not have more than 2 parameters in "+
363
                        "[method[%s] uri[%s]]", method, uri)
364
        }
365
        if typ.In(0) != constant.GinContextType {
366
                return errors.Errorf("router handler first parameter in should be *gin.Context "+
367
                        "[method[%s] uri[%s]]", method, uri)
368
        }
369
        if typ.NumIn() == 2 {
370
                if !r.checkParamType(typ.In(1), supportParamType) {
371
                        return errors.Errorf("router handler second parameter in type not supportted "+
372
                                "[method[%s] uri[%s]]", method, uri)
373
                }
374
        }
375
376
        // check out
377
378
        // check error
379
        if typ.NumOut() > 0 && !typ.Out(typ.NumOut()-1).AssignableTo(constant.ErrorType) {
380
                return errors.Errorf("router handler last paramater out should be error type "+
381
                        "[method[%s] uri[%s]]", method, uri)
382
        }
383
384
        // check (data any, page, count int, msg string, err error)
385
        if numOut := typ.NumOut(); numOut > 1 {
386
                supportTypes := supportReturnTypeList[numOut-1]
387
                for i := 0; i < numOut-1; i++ {
388
                        if !r.checkParamType(typ.Out(i), supportTypes[i]) {
389
                                return errors.Errorf("router handler paramater out format is illegal "+
390
                                        "[method[%s] uri[%s] index[%v] unsupported[%s] suppoted[%+v]]",
391
                                        method, uri, i+1, typ.Out(i).Kind(), supportTypes[i])
392
                        }
393
                }
394
        }
395
396
        return
397
}
func ginZeroCopyWriter.ReadFrom
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

49
func (z *ginZeroCopyWriter) ReadFrom(r io.Reader) (n int64, err error) {
50
        var size int64
51
        if limitedReader, ok := r.(*io.LimitedReader); ok {
52
                size = limitedReader.N
53
        }
54
55
        // forces to write the http header (status code + headers)
56
        z.ResponseWriter.WriteHeaderNow()
57
        if z.ctx.Request.Method == http.MethodHead {
58
                return size, nil
59
        }
60
61
        // hijack conn to call zero copy
62
        var conn net.Conn
63
        _, err = utils.Catch(func() (err error) { conn, _, err = z.ResponseWriter.Hijack(); return })
64
        if err != nil || conn == nil {
65
                // write by memory buffer
66
                if size > 0 {
67
                        return io.CopyN(z.ResponseWriter, r.(*io.LimitedReader), size)
68
                }
69
                return io.Copy(z.ResponseWriter, r)
70
        }
71
        defer func() {
72
                if closeErr := conn.Close(); closeErr != nil {
73
                        err = multierr.Append(err, closeErr)
74
                }
75
        }()
76
77
        // set write timeout again because it is reset when hijack
78
        if err = conn.SetWriteDeadline(time.Now().Add(gracefully.DefaultWriteTimeOut)); err != nil {
79
                return
80
        }
81
82
        // write body
83
        return io.Copy(conn, r)
84
}
func parseRspError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

677
func parseRspError(rspVals []reflect.Value, err error) (code int, data any, page, count int, msg string) {
678
        switch e := err.(type) {
679
        case Errcode:
680
                code, msg = int(e), e.Error()
681
        case *bizErr:
682
                code, msg = int(e.code), e.Error()
683
        default:
684
                code, msg = http.StatusBadRequest, e.Error()
685
        }
686
687
        data, page, count, retMsg := parseRspSuccess(rspVals)
688
        if retMsg != "" {
689
                msg = retMsg
690
        }
691
692
        return
693
}
func parseRspSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

655
func parseRspSuccess(rspVals []reflect.Value) (data any, page, count int, msg string) {
656
        switch {
657
        case len(rspVals) == 0:
658
        case len(rspVals) == 2:
659
                data = transformData(rspVals[0])
660
                msg = reflect.Indirect(rspVals[1]).String()
661
        case len(rspVals) == 3:
662
                data = transformData(rspVals[0])
663
                count = cast.ToInt(reflect.Indirect(rspVals[1]).Int())
664
                msg = reflect.Indirect(rspVals[2]).String()
665
        case len(rspVals) > 3:
666
                data = transformData(rspVals[0])
667
                page = cast.ToInt(reflect.Indirect(rspVals[1]).Int())
668
                count = cast.ToInt(reflect.Indirect(rspVals[2]).Int())
669
                msg = reflect.Indirect(rspVals[3]).String()
670
        default:
671
                data, page, count, msg = lookupFieldByStruct(rspVals[0])
672
        }
673
674
        return
675
}
func transformData
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

774
func transformData(data reflect.Value) (transformed any) {
775
        if !data.IsValid() {
776
                return
777
        }
778
779
        // some structs return as an interface
780
        if data.Kind() == reflect.Interface {
781
                data = reflect.ValueOf(data.Interface())
782
        }
783
        if data = utils.IndirectValue(data); !data.IsValid() {
784
                return
785
        }
786
787
        return data.Interface()
788
}
func @30:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

30
func(c *gin.Context) {
31
                name, modTime, content, err := fn(c)
32
                if err != nil {
33
                        code, data, page, count, msg := parseRspError(nil, err)
34
                        rspError(c, opt.appName, code, data, page, count, msg)
35
                        c.Abort()
36
                        return
37
                }
38
                defer utils.CloseAnyway(content)
39
                http.ServeContent(&ginZeroCopyWriter{ResponseWriter: c.Writer, ctx: c}, c.Request, name, modTime, content)
40
        }
func embedResponse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/response.go:

97
func embedResponse(c *gin.Context, data any, err error) {
98
        status := c.Writer.Status()
99
        if status == 0 {
100
                if err != nil {
101
                        status = http.StatusOK
102
                } else {
103
                        status = http.StatusBadRequest
104
                }
105
        }
106
107
        c.PureJSON(status, data)
108
}
func router.useIRouter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

265
func (r *router) useIRouter() gin.IRouter {
266
        switch r.ptr {
267
        case dispatchIRouter:
268
                return r.IRouter
269
        case dispatchGroup:
270
                return r.group
271
        case dispatchRoutes:
272
                panic(errors.New("group method unsupported for gin.Routes interface"))
273
        default:
274
                return r.IRouter
275
        }
276
}
func applyClientOptions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

145
func applyClientOptions(src *resty.Client, opt *clientOption) (dst *resty.Client) {
146
RetryConditionLoop:
147
        for _, cond := range opt.retryConditions {
148
                condName := utils.GetFuncName(cond)
149
                for _, exist := range src.RetryConditions {
150
                        if condName == utils.GetFuncName(exist) {
151
                                break RetryConditionLoop
152
                        }
153
                }
154
                src.AddRetryCondition(cond)
155
        }
156
157
RetryHookLoop:
158
        for _, hook := range opt.retryHooks {
159
                condName := utils.GetFuncName(hook)
160
                for _, exist := range src.RetryHooks {
161
                        if condName == utils.GetFuncName(exist) {
162
                                break RetryHookLoop
163
                        }
164
                }
165
                src.AddRetryHook(hook)
166
        }
167
168
        return src
169
}
func router.ListenAndServe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

168
func (r *router) ListenAndServe() (err error) {
169
        if _, ok := utils.IsChannelClosed(r.open); ok {
170
                <-r.Closing()
171
                return
172
        }
173
174
        conf := r.Config()
175
        gracefully.DefaultReadTimeOut = conf.ReadTimeout
176
        gracefully.DefaultWriteTimeOut = conf.WriteTimeout
177
        gracefully.DefaultMaxHeaderBytes = 1 << 20 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
178
179
        port := fmt.Sprintf(":%v", conf.Port)
180
        srv := gracefully.NewServer(r.appName, r.IRouter.(*gin.Engine), port, conf.NextProtos)
181
        r.shutdownFunc = srv.Shutdown
182
183
        r.close = make(chan struct{})
184
        close(r.open)
185
        defer func() {
186
                close(r.close)
187
                r.open = make(chan struct{})
188
        }()
189
190
        if conf.TLS {
191
                return srv.ListenAndServeTLS(conf.Cert, conf.Key)
192
        } else {
193
                return srv.ListenAndServe()
194
        }
195
}
func langs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/response.go:

110
func langs(c *gin.Context) (langs []string) {
111
        if c == nil {
112
                return
113
        }
114
        langs = c.Request.Header.Values("Accept-Language")
115
        if lang := c.GetString("lang"); utils.IsStrNotBlank(lang) {
116
                langs = append(langs, lang)
117
        }
118
        if lang := c.GetString(fusCtx.KeyLangs); utils.IsStrNotBlank(lang) {
119
                langs = append(langs, lang)
120
        }
121
        return langs
122
}
func Localizable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/i18n.go:

15
func Localizable(opts ...utils.OptionExtender) i18n.Localizable[Errcode] {
16
        opt := utils.ApplyOptions[useOption](opts...)
17
18
        locker.RLock()
19
        defer locker.RUnlock()
20
        i, ok := i18ns[opt.appName]
21
        if !ok {
22
                panic(errors.Errorf("http i18n not founc: %s", opt.appName))
23
        }
24
        return i
25
}
func @101:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

101
func(c *gin.Context) {
102
                c.Status(http.StatusNotFound)
103
                msg := fmt.Sprintf("找不到该内容, URL: %s", c.Request.URL.String())
104
                if tag != language.Chinese {
105
                        msg = fmt.Sprintf("Cannot find URL content: %s", c.Request.URL.String())
106
                }
107
                rspError(c, opt.AppName, -1, nil, 0, 0, msg)
108
        }
func @92:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

92
func(c *gin.Context) {
93
                c.Status(http.StatusMethodNotAllowed)
94
                msg := fmt.Sprintf("找不到该方法, Method: %s", c.Request.Method)
95
                if tag != language.Chinese {
96
                        msg = fmt.Sprintf("Cannot find method: %s", c.Request.Method)
97
                }
98
99
                rspError(c, opt.AppName, -1, nil, 0, 0, msg)
100
        }
func ErrCtx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

67
func ErrCtx(ctx context.Context, code Errcode, opts ...utils.OptionExtender) error {
68
        opt := utils.ApplyOptions[errOption](opts...)
69
        if len(opt.langs) == 0 {
70
                opt.langs = fusCtx.GetLangs(ctx)
71
        }
72
        return &bizErr{
73
                code:      code,
74
                errOption: opt,
75
        }
76
}
func Err
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

55
func Err(c *gin.Context, code Errcode, opts ...utils.OptionExtender) error {
56
        opt := utils.ApplyOptions[errOption](opts...)
57
        if len(opt.langs) == 0 {
58
                opt.langs = langs(c)
59
        }
60
        return &bizErr{
61
                code:      code,
62
                errOption: opt,
63
        }
64
}
func router.Handle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

95
func (r *router) Handle(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
96
        opt := utils.ApplyOptions[routerOption](opts...)
97
        r.use().HEAD(uri, r.convertMulti("Handle", uri, fn, opt)...)
98
        return r
99
}
func bizErr.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

83
func (b *bizErr) Error() (r string) {
84
        if b.msg != "" {
85
                return b.msg
86
        }
87
        return I18n.Localize(b.code, i18n.Langs(b.langs), i18n.Param(b.param))
88
}
func router.HEAD
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

135
func (r *router) HEAD(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
136
        opt := utils.ApplyOptions[routerOption](opts...)
137
        r.use().HEAD(uri, r.convertMulti(http.MethodHead, uri, fn, opt)...)
138
        return r
139
}
func router.PATCH
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

120
func (r *router) PATCH(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
121
        opt := utils.ApplyOptions[routerOption](opts...)
122
        r.use().PATCH(uri, r.convertMulti(http.MethodPatch, uri, fn, opt)...)
123
        return r
124
}
func router.DELETE
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

115
func (r *router) DELETE(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
116
        opt := utils.ApplyOptions[routerOption](opts...)
117
        r.use().DELETE(uri, r.convertMulti(http.MethodDelete, uri, fn, opt)...)
118
        return r
119
}
func @43:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

43
func(o *clientOption) {
44
                o.mu.Lock()
45
                defer o.mu.Unlock()
46
                o.retryConditions = append(o.retryConditions, fn)
47
        }
func @51:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

51
func(o *clientOption) {
52
                o.mu.Lock()
53
                defer o.mu.Unlock()
54
                o.retryHooks = append(o.retryHooks, fn)
55
        }
func router.PUT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

125
func (r *router) PUT(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
126
        opt := utils.ApplyOptions[routerOption](opts...)
127
        r.use().PUT(uri, r.convertMulti(http.MethodPut, uri, fn, opt)...)
128
        return r
129
}
func router.OPTIONS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

130
func (r *router) OPTIONS(uri string, fn routerHandler, opts ...utils.OptionExtender) IRouter {
131
        opt := utils.ApplyOptions[routerOption](opts...)
132
        r.use().OPTIONS(uri, r.convertMulti(http.MethodOptions, uri, fn, opt)...)
133
        return r
134
}
func router.StaticFileFS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

155
func (r *router) StaticFileFS(uri, file string, fs http.FileSystem) IRouter {
156
        r.use().StaticFileFS(uri, file, fs)
157
        return r
158
}
func router.Static
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

159
func (r *router) Static(uri, file string) IRouter { r.use().Static(uri, file); return r }
func router.StaticFS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

160
func (r *router) StaticFS(uri string, fs http.FileSystem) IRouter {
161
        r.use().StaticFS(uri, fs)
162
        return r
163
}
func @185:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

185
func() {
186
                close(r.close)
187
                r.open = make(chan struct{})
188
        }
func @71:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/zerocopy.go:

71
func() {
72
                if closeErr := conn.Close(); closeErr != nil {
73
                        err = multierr.Append(err, closeErr)
74
                }
75
        }
func Langs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

36
func Langs(c *gin.Context) utils.OptionFunc[errOption] {
37
        return func(e *errOption) {
38
                e.langs = langs(c)
39
        }
40
}
func @129:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

129
func() IRouter { return Use(AppName(opt.AppName)) }
func @219:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/construct.go:

219
func() *resty.Client { return New(AppName(opt.AppName), CName(name)) }
func Errcode.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

26
func (e Errcode) Error() (r string) {
27
        return I18n.Localize(e)
28
}
func @37:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

37
func(e *errOption) {
38
                e.langs = langs(c)
39
        }
func @797:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

797
func(r *routerOption) {
798
                r.parseFrom = parseFromBody
799
        }
func ParseFromQuery
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

802
func ParseFromQuery() utils.OptionFunc[routerOption] {
803
        return func(r *routerOption) {
804
                r.parseFrom = parseFromQuery
805
        }
806
}
func @803:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

803
func(r *routerOption) {
804
                r.parseFrom = parseFromQuery
805
        }
func HandleBefore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

808
func HandleBefore(beforeHandlers ...routerHandler) utils.OptionFunc[routerOption] {
809
        return func(o *routerOption) {
810
                o.beforeHandlers = beforeHandlers
811
        }
812
}
func @809:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

809
func(o *routerOption) {
810
                o.beforeHandlers = beforeHandlers
811
        }
func HandleAfter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

814
func HandleAfter(aftersHandlers ...routerHandler) utils.OptionFunc[routerOption] {
815
        return func(o *routerOption) {
816
                o.aftersHandlers = aftersHandlers
817
        }
818
}
func @815:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

815
func(o *routerOption) {
816
                o.aftersHandlers = aftersHandlers
817
        }
func Param
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

42
func Param(param map[string]any) utils.OptionFunc[errOption] {
43
        return func(e *errOption) {
44
                e.param = param
45
        }
46
}
func RetryHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

50
func RetryHook(fn resty.OnRetryFunc) utils.OptionFunc[clientOption] {
51
        return func(o *clientOption) {
52
                o.mu.Lock()
53
                defer o.mu.Unlock()
54
                o.retryHooks = append(o.retryHooks, fn)
55
        }
56
}
func @43:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

43
func(e *errOption) {
44
                e.param = param
45
        }
func ParseFromBody
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/router.go:

796
func ParseFromBody() utils.OptionFunc[routerOption] {
797
        return func(r *routerOption) {
798
                r.parseFrom = parseFromBody
799
        }
800
}
func Msg
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

48
func Msg(msg string) utils.OptionFunc[errOption] {
49
        return func(e *errOption) {
50
                e.msg = msg
51
        }
52
}
func RetryCondition
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/client.go:

42
func RetryCondition(fn resty.RetryConditionFunc) utils.OptionFunc[clientOption] {
43
        return func(o *clientOption) {
44
                o.mu.Lock()
45
                defer o.mu.Unlock()
46
                o.retryConditions = append(o.retryConditions, fn)
47
        }
48
}
func @49:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/error.go:

49
func(e *errOption) {
50
                e.msg = msg
51
        }
Package Overview: github.com/wfusion/gofusion/http/consts 88.9%

Please select a function to see what's left for testing.

SetReqStartTime(...) github.com/wfusion/gofusion/http/consts/context.go 100.0% 1/1
GetReqCost(...) github.com/wfusion/gofusion/http/consts/context.go 87.5% 7/8
func SetReqStartTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/consts/context.go:

15
func SetReqStartTime(c *gin.Context) {
16
        c.Set(ctxReqStartAtKey, time.Now())
17
}
func GetReqCost
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/consts/context.go:

19
func GetReqCost(c *gin.Context) time.Duration {
20
        if cost, ok := c.Get(ctxReqCostKey); ok {
21
                return cast.ToDuration(cost)
22
        }
23
24
        start := time.Now()
25
        if _, ok := c.Get(ctxReqStartAtKey); ok {
26
                start = c.GetTime(ctxReqStartAtKey)
27
        }
28
        cost := time.Since(start)
29
        c.Set(ctxReqCostKey, cost)
30
        return cost
31
}
Package Overview: github.com/wfusion/gofusion/http/gracefully 37.8%

Please select a function to see what's left for testing.

endlessServer.Serve(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 11/11
endlessListener.Accept(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 8/8
init(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 6/6
endlessServer.setState(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 3/3
endlessServer.getState(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 3/3
endlessConn.Close(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 2/2
endlessConn.SetReadDeadline(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
endlessConn.RemoteAddr(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
endlessConn.SetWriteDeadline(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
@505:22(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
endlessConn.Write(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/http/gracefully/signal_darwin.go 100.0% 1/1
newSignalHookFunc(...) github.com/wfusion/gofusion/http/gracefully/signal_darwin.go 100.0% 1/1
newEndlessListener(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
endlessConn.LocalAddr(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
endlessConn.Read(...) github.com/wfusion/gofusion/http/gracefully/endless.go 100.0% 1/1
NewServer(...) github.com/wfusion/gofusion/http/gracefully/endless.go 83.3% 10/12
endlessServer.Shutdown(...) github.com/wfusion/gofusion/http/gracefully/endless.go 80.0% 8/10
endlessListener.Close(...) github.com/wfusion/gofusion/http/gracefully/signal_darwin.go 75.0% 3/4
endlessServer.ListenAndServe(...) github.com/wfusion/gofusion/http/gracefully/endless.go 62.5% 10/16
@356:8(...) github.com/wfusion/gofusion/http/gracefully/endless.go 50.0% 1/2
endlessServer.hammerTime(...) github.com/wfusion/gofusion/http/gracefully/endless.go 30.0% 3/10
endlessServer.getListener(...) github.com/wfusion/gofusion/http/gracefully/endless.go 23.5% 4/17
endlessServer.handleSignals(...) github.com/wfusion/gofusion/http/gracefully/signal_darwin.go 15.8% 6/38
endlessServer.fork(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/27
endlessServer.ListenAndServeTLS(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/26
endlessServer.RegisterSignalHook(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/9
endlessServer.signalHooks(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/4
endlessListener.File(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/3
ListenAndServe(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/2
ListenAndServeTLS(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/2
endlessConn.SetKeepAlive(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.SetKeepAlivePeriod(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.SetNoDelay(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.SetLinger(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.ReadFrom(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.SyscallConn(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
endlessConn.SetDeadline(...) github.com/wfusion/gofusion/http/gracefully/endless.go 0.0% 0/1
syscallKill(...) github.com/wfusion/gofusion/http/gracefully/signal_darwin.go 0.0% 0/1
func endlessServer.Serve
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

156
func (e *endlessServer) Serve() (err error) {
157
        defer log.Println(syscall.Getpid(), "[Common] endless exited.")
158
159
        e.setState(StateRunning)
160
        log.Println(syscall.Getpid(), "[Common] endless listening", e.endlessListener.Addr())
161
162
        // ignore server closed error because it happened when we call Server.Shutdown or Server.Close
163
        if err = e.Server.Serve(e.endlessListener); err != nil {
164
                // http: Server closed
165
                // use of closed network connection
166
                if errors.Is(err, http.ErrServerClosed) || isClosedConnError(err) {
167
                        err = nil
168
                }
169
        }
170
        log.Println(syscall.Getpid(), "[Common] endless waiting for connections to finish...")
171
        e.wg.Wait()
172
        e.setState(StateTerminate)
173
174
        <-e.close
175
176
        return
177
}
func endlessListener.Accept
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

459
func (e *endlessListener) Accept() (c net.Conn, err error) {
460
        tc, err := e.Listener.(*net.TCPListener).AcceptTCP()
461
        if err != nil {
462
                return
463
        }
464
465
        // see net/http.tcpKeepAliveListener
466
        _ = tc.SetKeepAlive(true)
467
        // see net/http.tcpKeepAliveListener
468
        _ = tc.SetKeepAlivePeriod(3 * time.Minute)
469
470
        c = &endlessConn{
471
                Conn:   tc,
472
                server: e.server,
473
        }
474
475
        e.server.wg.Add(1)
476
        return
477
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

58
func init() {
59
        runningServerReg = sync.RWMutex{}
60
        runningServers = make(map[string]*endlessServer)
61
        runningServersOrder = []string{}
62
        socketPtrOffsetMap = make(map[string]uint)
63
64
        DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
65
66
        // after a restart the parent will finish ongoing requests before
67
        // shutting down. set to a negative value to disable
68
        DefaultHammerTime = 60 * time.Second
69
}
func endlessServer.setState
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

439
func (e *endlessServer) setState(st uint8) {
440
        e.lock.Lock()
441
        defer e.lock.Unlock()
442
443
        e.state = st
444
}
func endlessServer.getState
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

432
func (e *endlessServer) getState() uint8 {
433
        e.lock.RLock()
434
        defer e.lock.RUnlock()
435
436
        return e.state
437
}
func endlessConn.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

504
func (e *endlessConn) Close() (err error) {
505
        defer e.doneOnce.Do(func() {
506
                e.server.wg.Done()
507
        })
508
        return e.Conn.Close()
509
}
func endlessConn.SetReadDeadline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

543
func (e *endlessConn) SetReadDeadline(t time.Time) error { return e.Conn.SetReadDeadline(t) }
func endlessConn.RemoteAddr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

515
func (e *endlessConn) RemoteAddr() net.Addr { return e.Conn.RemoteAddr() }
func endlessConn.SetWriteDeadline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

550
func (e *endlessConn) SetWriteDeadline(t time.Time) error { return e.Conn.SetWriteDeadline(t) }
func @505:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

505
func() {
506
                e.server.wg.Done()
507
        }
func endlessConn.Write
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

500
func (e *endlessConn) Write(b []byte) (n int, err error) { return e.Conn.Write(b) }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/signal_darwin.go:

15
func init() {
16
        hookableSignals = []os.Signal{
17
                syscall.SIGHUP,
18
                syscall.SIGUSR1,
19
                syscall.SIGUSR2,
20
                syscall.SIGINT,
21
                syscall.SIGQUIT,
22
                syscall.SIGTERM,
23
                syscall.SIGTSTP,
24
        }
25
}
func newSignalHookFunc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/signal_darwin.go:

27
func newSignalHookFunc() map[int]map[os.Signal][]func() {
28
        return map[int]map[os.Signal][]func(){
29
                PreSignal: {
30
                        syscall.SIGHUP:  []func(){},
31
                        syscall.SIGUSR1: []func(){},
32
                        syscall.SIGUSR2: []func(){},
33
                        syscall.SIGINT:  []func(){},
34
                        syscall.SIGQUIT: []func(){},
35
                        syscall.SIGTERM: []func(){},
36
                        syscall.SIGTSTP: []func(){},
37
                },
38
                PostSignal: {
39
                        syscall.SIGHUP:  []func(){},
40
                        syscall.SIGUSR1: []func(){},
41
                        syscall.SIGUSR2: []func(){},
42
                        syscall.SIGINT:  []func(){},
43
                        syscall.SIGQUIT: []func(){},
44
                        syscall.SIGTERM: []func(){},
45
                        syscall.SIGTSTP: []func(){},
46
                },
47
        }
48
}
func newEndlessListener
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

452
func newEndlessListener(l net.Listener, srv *endlessServer) (el *endlessListener) {
453
        return &endlessListener{
454
                Listener: l,
455
                server:   srv,
456
        }
457
}
func endlessConn.LocalAddr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

512
func (e *endlessConn) LocalAddr() net.Addr { return e.Conn.LocalAddr() }
func endlessConn.Read
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

495
func (e *endlessConn) Read(b []byte) (n int, err error) { return e.Conn.Read(b) }
func NewServer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

89
func NewServer(appName string, handler http.Handler, addr string, nextProtos []string) (srv *endlessServer) {
90
        runningServerReg.Lock()
91
        defer runningServerReg.Unlock()
92
93
        socketOrder = os.Getenv("ENDLESS_SOCKET_ORDER")
94
        isChild = os.Getenv("ENDLESS_CONTINUE") != ""
95
96
        if len(socketOrder) > 0 {
97
                for i, addr := range strings.Split(socketOrder, ",") {
98
                        socketPtrOffsetMap[addr] = uint(i)
99
                }
100
        } else {
101
                socketPtrOffsetMap[addr] = uint(len(runningServersOrder))
102
        }
103
104
        srv = &endlessServer{
105
                AppName: appName,
106
                Server: &http.Server{
107
                        Addr:           addr,
108
                        ReadTimeout:    DefaultReadTimeOut,
109
                        WriteTimeout:   DefaultWriteTimeOut,
110
                        MaxHeaderBytes: DefaultMaxHeaderBytes,
111
                        Handler:        handler,
112
                        TLSConfig:      &tls.Config{NextProtos: nextProtos},
113
                },
114
                close:       make(chan struct{}),
115
                wg:          new(sync.WaitGroup),
116
                sigChan:     make(chan os.Signal),
117
                isChild:     isChild,
118
                SignalHooks: newSignalHookFunc(),
119
                state:       StateInit,
120
                lock:        new(sync.RWMutex),
121
        }
122
123
        runningServersOrder = append(runningServersOrder, addr)
124
        runningServers[addr] = srv
125
126
        return
127
}
func endlessServer.Shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

270
func (e *endlessServer) Shutdown() {
271
        // make sure server Shutdown & log printed before Serve() return
272
        defer close(e.close)
273
274
        if e.getState() != StateRunning {
275
                return
276
        }
277
278
        e.setState(StateShuttingDown)
279
        if DefaultHammerTime >= 0 {
280
                routine.Loop(e.hammerTime, routine.Args(DefaultHammerTime), routine.AppName(e.AppName))
281
        }
282
        // disable keep-alive on existing connections
283
        e.Server.SetKeepAlivesEnabled(false)
284
285
        // TODO: new context with timeout because system may forcefully kill the program
286
        if err := e.Server.Shutdown(context.TODO()); err != nil {
287
                log.Println(syscall.Getpid(), "[Common] endless close listener error:", err)
288
        } else {
289
                log.Println(syscall.Getpid(), "[Common] endless", e.endlessListener.Addr(), "listener closed.")
290
        }
291
}
func endlessListener.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/signal_darwin.go:

113
func (e *endlessListener) Close() error {
114
        if e.stopped {
115
                return syscall.EINVAL
116
        }
117
118
        e.stopped = true
119
        return e.Listener.Close()
120
}
func endlessServer.ListenAndServe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

182
func (e *endlessServer) ListenAndServe() (err error) {
183
        addr := e.Addr
184
        if addr == "" {
185
                addr = ":http"
186
        }
187
188
        if err = setupHTTP2_Serve(e.Server); err != nil {
189
                return
190
        }
191
192
        routine.Go(e.handleSignals, routine.AppName(e.AppName))
193
194
        l, err := e.getListener(addr)
195
        if err != nil {
196
                log.Println(syscall.Getpid(), "[Common] endless", err)
197
                return
198
        }
199
200
        e.endlessListener = newEndlessListener(l, e)
201
        if e.isChild {
202
                _ = syscallKill(syscall.Getppid())
203
        }
204
205
        if e.BeforeBegin != nil {
206
                e.BeforeBegin(e.Addr)
207
        }
208
209
        return e.Serve()
210
}
func @356:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

356
func() {
357
                // we are calling e.wg.Done() until it panics which means we called
358
                // Done() when the counter was already at 0, and we're done.
359
                // (and thus Serve() will return and the parent will exit)
360
                if r := recover(); r != nil {
361
                        log.Println(syscall.Getpid(), "[Common] endless wait group at 0", r)
362
                }
363
        }
func endlessServer.hammerTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

355
func (e *endlessServer) hammerTime(d time.Duration) {
356
        defer func() {
357
                // we are calling e.wg.Done() until it panics which means we called
358
                // Done() when the counter was already at 0, and we're done.
359
                // (and thus Serve() will return and the parent will exit)
360
                if r := recover(); r != nil {
361
                        log.Println(syscall.Getpid(), "[Common] endless wait group at 0", r)
362
                }
363
        }()
364
        if e.getState() != StateShuttingDown {
365
                return
366
        }
367
        time.Sleep(d)
368
        log.Println(syscall.Getpid(), "[Common] endless harmerTime() forcefully shutting down parent")
369
        for {
370
                if e.getState() == StateTerminate {
371
                        break
372
                }
373
                e.wg.Done()
374
                runtime.Gosched()
375
        }
376
}
func endlessServer.getListener
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

313
func (e *endlessServer) getListener(addr string) (l net.Listener, err error) {
314
        if e.isChild {
315
                ptrOffset := uint(0)
316
                runningServerReg.RLock()
317
                defer runningServerReg.RUnlock()
318
                if len(socketPtrOffsetMap) > 0 {
319
                        ptrOffset = socketPtrOffsetMap[addr]
320
                        log.Println(syscall.Getpid(), "[Common] endless addr:", addr, "ptr offset:", socketPtrOffsetMap[addr])
321
                }
322
323
                f := os.NewFile(uintptr(3+ptrOffset), "")
324
                l, err = net.FileListener(f)
325
                if err != nil {
326
                        err = fmt.Errorf("net.FileListener error: %v", err)
327
                        return
328
                }
329
        } else {
330
                l, err = net.Listen("tcp", addr)
331
                if err != nil {
332
                        err = fmt.Errorf("net.Listen error: %v", err)
333
                        return
334
                }
335
        }
336
        return
337
}
func endlessServer.handleSignals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/signal_darwin.go:

52
func (e *endlessServer) handleSignals() {
53
        var sig os.Signal
54
55
        signal.Notify(
56
                e.sigChan,
57
                hookableSignals...,
58
        )
59
60
        pid := syscall.Getpid()
61
        for {
62
                select {
63
                case sig = <-e.sigChan:
64
                case <-e.close:
65
                        return
66
                }
67
68
                e.signalHooks(PreSignal, sig)
69
                switch sig {
70
                case syscall.SIGHUP:
71
                        signal.Stop(e.sigChan)
72
                        close(e.sigChan)
73
                        log.Println(pid, "[Common] endless received SIGHUP. forking...")
74
                        if err := e.fork(); err != nil {
75
                                log.Println("[Common] endless fork err:", err)
76
                        }
77
                        return
78
                case syscall.SIGUSR1:
79
                        log.Println(pid, "[Common] endless received SIGUSR1.")
80
                case syscall.SIGUSR2:
81
                        signal.Stop(e.sigChan)
82
                        close(e.sigChan)
83
                        log.Println(pid, "[Common] endless received SIGUSR2.")
84
                        e.hammerTime(0 * time.Second)
85
                        return
86
                case syscall.SIGINT:
87
                        signal.Stop(e.sigChan)
88
                        close(e.sigChan)
89
                        log.Println(pid, "[Common] endless received SIGINT.")
90
                        e.Shutdown()
91
                        return
92
                case syscall.SIGQUIT:
93
                        signal.Stop(e.sigChan)
94
                        close(e.sigChan)
95
                        log.Println(pid, "[Common] endless received SIGQUIT.")
96
                        e.Shutdown()
97
                        return
98
                case syscall.SIGTERM:
99
                        signal.Stop(e.sigChan)
100
                        close(e.sigChan)
101
                        log.Println(pid, "[Common] endless received SIGTERM.")
102
                        e.Shutdown()
103
                        return
104
                case syscall.SIGTSTP:
105
                        log.Println(pid, "[Common] endless received SIGTSTP.")
106
                default:
107
                        log.Printf("[Common] endless received %v: nothing we care about...\n", sig)
108
                }
109
                e.signalHooks(PostSignal, sig)
110
        }
111
}
func endlessServer.fork
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

378
func (e *endlessServer) fork() (err error) {
379
        runningServerReg.Lock()
380
        defer runningServerReg.Unlock()
381
382
        // only one server instance should fork!
383
        if runningServersForked {
384
                return errors.New("another process already forked, ignoring this one")
385
        }
386
387
        runningServersForked = true
388
389
        var files = make([]*os.File, len(runningServers))
390
        var orderArgs = make([]string, len(runningServers))
391
        // get the accessor socket fds for _all_ server instances
392
        for _, srvPtr := range runningServers {
393
                // introspect.PrintTypeDump(srvPtr.endlessListener)
394
                switch srvPtr.endlessListener.(type) {
395
                case *endlessListener:
396
                        // normal listener
397
                        files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.endlessListener.(*endlessListener).File()
398
                default:
399
                        // tls listener
400
                        files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
401
                }
402
                orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
403
        }
404
405
        env := append(
406
                os.Environ(),
407
                "ENDLESS_CONTINUE=1",
408
        )
409
        if len(runningServers) > 1 {
410
                env = append(env, fmt.Sprintf(`ENDLESS_SOCKET_ORDER=%s`, strings.Join(orderArgs, ",")))
411
        }
412
413
        path := os.Args[0]
414
        var args []string
415
        if len(os.Args) > 1 {
416
                args = os.Args[1:]
417
        }
418
419
        cmd := exec.Command(path, args...)
420
        cmd.Stdout = os.Stdout
421
        cmd.Stderr = os.Stderr
422
        cmd.ExtraFiles = files
423
        cmd.Env = env
424
425
        if err = cmd.Start(); err != nil {
426
                log.Fatalf("%v [Common] endless restart: failed to launch, error: %v", syscall.Getpid(), err)
427
        }
428
429
        return
430
}
func endlessServer.ListenAndServeTLS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

221
func (e *endlessServer) ListenAndServeTLS(certFile, keyFile string) (err error) {
222
        addr := e.Addr
223
        if addr == "" {
224
                addr = ":https"
225
        }
226
227
        // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
228
        // before we clone it and create the TLS Listener.
229
        if err = setupHTTP2_ServeTLS(e.Server); err != nil {
230
                return
231
        }
232
233
        config := new(tls.Config)
234
        if e.Server.TLSConfig != nil {
235
                *config = *e.Server.TLSConfig.Clone()
236
        }
237
        if !utils.NewSet(config.NextProtos...).Contains("http/1.1") {
238
                config.NextProtos = append(config.NextProtos, "http/1.1")
239
        }
240
241
        configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil
242
        if !configHasCert || certFile != "" || keyFile != "" {
243
                config.Certificates = make([]tls.Certificate, 1)
244
                config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
245
                if err != nil {
246
                        return err
247
                }
248
        }
249
250
        routine.Go(e.handleSignals, routine.AppName(e.AppName))
251
252
        l, err := e.getListener(addr)
253
        if err != nil {
254
                log.Println(syscall.Getpid(), "[Common] endless error occur when get listener:", err)
255
                return
256
        }
257
258
        e.tlsInnerListener = newEndlessListener(l, e)
259
        e.endlessListener = tls.NewListener(e.tlsInnerListener, config)
260
        if e.isChild {
261
                _ = syscallKill(syscall.Getppid())
262
        }
263
264
        return e.Serve()
265
}
func endlessServer.RegisterSignalHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

296
func (e *endlessServer) RegisterSignalHook(prePost int, sig os.Signal, f func()) (err error) {
297
        if prePost != PreSignal && prePost != PostSignal {
298
                err = fmt.Errorf("cannot use %v for prePost arg. Must be endless.PRE_SIGNAL or endless.POST_SIGNAL", sig)
299
                return
300
        }
301
        for _, s := range hookableSignals {
302
                if s == sig {
303
                        e.SignalHooks[prePost][sig] = append(e.SignalHooks[prePost][sig], f)
304
                        return
305
                }
306
        }
307
        err = fmt.Errorf("signal %v is not supported", sig)
308
        return
309
}
func endlessServer.signalHooks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

339
func (e *endlessServer) signalHooks(ppFlag int, sig os.Signal) {
340
        if _, notSet := e.SignalHooks[ppFlag][sig]; !notSet {
341
                return
342
        }
343
        for _, f := range e.SignalHooks[ppFlag][sig] {
344
                f()
345
        }
346
}
func endlessListener.File
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

479
func (e *endlessListener) File() *os.File {
480
        // returns a dup(2) - FD_CLOEXEC flag *not* set
481
        tl := e.Listener.(*net.TCPListener)
482
        fl, _ := tl.File()
483
        return fl
484
}
func ListenAndServe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

132
func ListenAndServe(appName string, handler http.Handler, addr string, nextProtos []string) error {
133
        server := NewServer(appName, handler, addr, nextProtos)
134
        return server.ListenAndServe()
135
}
func ListenAndServeTLS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

142
func ListenAndServeTLS(appName string, handler http.Handler, addr, certFile, keyFile string,
143
        nextProtos []string) error {
144
        server := NewServer(appName, handler, addr, nextProtos)
145
        return server.ListenAndServeTLS(certFile, keyFile)
146
}
func endlessConn.SetKeepAlive
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

581
func (e *endlessConn) SetKeepAlive(keepalive bool) error {
582
        return e.Conn.(*net.TCPConn).SetKeepAlive(keepalive)
583
}
func endlessConn.SetKeepAlivePeriod
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

586
func (e *endlessConn) SetKeepAlivePeriod(d time.Duration) error {
587
        return e.Conn.(*net.TCPConn).SetKeepAlivePeriod(d)
588
}
func endlessConn.SetNoDelay
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

594
func (e *endlessConn) SetNoDelay(noDelay bool) error {
595
        return e.Conn.(*net.TCPConn).SetNoDelay(noDelay)
596
}
func endlessConn.SetLinger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

575
func (e *endlessConn) SetLinger(sec int) error {
576
        return e.Conn.(*net.TCPConn).SetLinger(sec)
577
}
func endlessConn.ReadFrom
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

559
func (e *endlessConn) ReadFrom(r io.Reader) (int64, error) {
560
        return e.Conn.(*net.TCPConn).ReadFrom(r)
561
}
func endlessConn.SyscallConn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

554
func (e *endlessConn) SyscallConn() (syscall.RawConn, error) {
555
        return e.Conn.(*net.TCPConn).SyscallConn()
556
}
func endlessConn.SetDeadline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/endless.go:

538
func (e *endlessConn) SetDeadline(t time.Time) error { return e.Conn.SetDeadline(t) }
func syscallKill
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/gracefully/signal_darwin.go:

122
func syscallKill(ppid int) error {
123
        return syscall.Kill(ppid, syscall.SIGTERM)
124
}
Package Overview: github.com/wfusion/gofusion/http/middleware 53.3%

Please select a function to see what's left for testing.

@12:9(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 7/7
@120:9(...) github.com/wfusion/gofusion/http/middleware/logging.go 100.0% 3/3
@29:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
@38:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
@34:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
@18:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
@19:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
Recover(...) github.com/wfusion/gofusion/http/middleware/recover.go 100.0% 2/2
@26:9(...) github.com/wfusion/gofusion/http/middleware/recover.go 100.0% 2/2
@30:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
@17:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
XSS(...) github.com/wfusion/gofusion/http/middleware/xss.go 100.0% 2/2
@23:4(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 2/2
Trace(...) github.com/wfusion/gofusion/http/middleware/trace.go 100.0% 1/1
Logging(...) github.com/wfusion/gofusion/http/middleware/logging.go 100.0% 1/1
Gateway(...) github.com/wfusion/gofusion/http/middleware/gateway.go 100.0% 1/1
Cors(...) github.com/wfusion/gofusion/http/middleware/cors.go 100.0% 1/1
metricsLogging(...) github.com/wfusion/gofusion/http/middleware/logging.go 78.6% 11/14
logging(...) github.com/wfusion/gofusion/http/middleware/logging.go 78.6% 11/14
@12:9(...) github.com/wfusion/gofusion/http/middleware/cors.go 63.2% 12/19
@27:9(...) github.com/wfusion/gofusion/http/middleware/recover.go 60.5% 23/38
@22:9(...) github.com/wfusion/gofusion/http/middleware/xss.go 12.1% 4/33
xssFilterJSON(...) github.com/wfusion/gofusion/http/middleware/xss.go 0.0% 0/9
xssFilterJSONData(...) github.com/wfusion/gofusion/http/middleware/xss.go 0.0% 0/9
xssFilterQuery(...) github.com/wfusion/gofusion/http/middleware/xss.go 0.0% 0/8
xssFilterPlain(...) github.com/wfusion/gofusion/http/middleware/xss.go 0.0% 0/2
func @12:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

12
func(c *gin.Context) {
13
                var (
14
                        userID, traceID string
15
                )
16
                utils.IfAny(
17
                        func() bool { traceID = c.GetHeader(fusCtx.KeyTraceID); return traceID != "" },
18
                        func() bool { traceID = c.GetHeader("HTTP_TRACE_ID"); return traceID != "" },
19
                        func() bool {
20
                                traceID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "trace_id")
21
                                return traceID != ""
22
                        },
23
                        func() bool { traceID = utils.NginxID(); return traceID != "" },
24
                )
25
                c.Header("Trace-Id", traceID)
26
                c.Set(fusCtx.KeyTraceID, traceID)
27
28
                utils.IfAny(
29
                        func() bool { userID = c.GetHeader(fusCtx.KeyUserID); return userID != "" },
30
                        func() bool {
31
                                userID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "user_id")
32
                                return userID != ""
33
                        },
34
                        func() bool {
35
                                userID = utils.LookupByFuzzyKeyword[string](c.GetQuery, "user_id")
36
                                return userID != ""
37
                        },
38
                        func() bool {
39
                                userID = utils.LookupByFuzzyKeyword[string](c.GetPostForm, "user_id")
40
                                return userID != ""
41
                        },
42
                )
43
                c.Set(fusCtx.KeyUserID, userID)
44
                c.Next()
45
        }
func @120:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/logging.go:

120
func(c *gin.Context) {
121
                reqURL := clone.Clone(c.Request.URL)
122
                defer logging(ctx, c, logger, reqURL, appName)
123
124
                c.Next()
125
        }
func @29:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

29
func() bool { userID = c.GetHeader(fusCtx.KeyUserID); return userID != "" }
func @38:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

38
func() bool {
39
                                userID = utils.LookupByFuzzyKeyword[string](c.GetPostForm, "user_id")
40
                                return userID != ""
41
                        }
func @34:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

34
func() bool {
35
                                userID = utils.LookupByFuzzyKeyword[string](c.GetQuery, "user_id")
36
                                return userID != ""
37
                        }
func @18:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

18
func() bool { traceID = c.GetHeader("HTTP_TRACE_ID"); return traceID != "" }
func @19:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

19
func() bool {
20
                                traceID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "trace_id")
21
                                return traceID != ""
22
                        }
func Recover
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/recover.go:

24
func Recover(appName string, logger resty.Logger) gin.HandlerFunc {
25
        tag := i18n.DefaultLang(i18n.AppName(appName))
26
        return func(c *gin.Context) {
27
                defer func() {
28
                        if err := recover(); err != nil {
29
                                // Check for a broken connection, as it is not really a
30
                                // condition that warrants a panic stack trace.
31
                                var brokenPipe bool
32
                                if ne, ok := err.(*net.OpError); ok {
33
                                        if se, ok := ne.Err.(*os.SyscallError); ok {
34
                                                if strings.Contains(strings.ToLower(se.Error()), "broken pipe") ||
35
                                                        strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
36
                                                        brokenPipe = true
37
                                                }
38
                                        }
39
                                }
40
                                if brokenPipe {
41
                                        c.Abort()
42
                                        return
43
                                }
44
                                debugStack := ""
45
                                for _, v := range strings.Split(string(debug.Stack()), "\n") {
46
                                        debugStack += "> " + v + "\n"
47
                                }
48
                                hostname, hostnameErr := os.Hostname()
49
                                if hostnameErr != nil {
50
                                        hostname = "unknown"
51
                                }
52
                                buffer, cb := utils.BytesBufferPool.Get(nil)
53
                                defer cb()
54
55
                                if tag == language.Chinese {
56
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
57
                                        buffer.WriteString(fmt.Sprintf("请求时间:%v \n", time.Now().Format(constant.StdTimeLayout)))
58
                                        buffer.WriteString(fmt.Sprintf("主机名称:%v \n", hostname))
59
                                        buffer.WriteString(fmt.Sprintf("请求编号:%v \n", c.GetString(fusCtx.KeyTraceID)))
60
                                        buffer.WriteString(fmt.Sprintf("请求地址:%v \n",
61
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
62
                                        buffer.WriteString(fmt.Sprintf("请求UA:%v \n", c.Request.UserAgent()))
63
                                        buffer.WriteString(fmt.Sprintf("请求IP:%v \n", c.ClientIP()))
64
                                        buffer.WriteString(fmt.Sprintf("异常捕获:\n%v", debugStack))
65
                                } else {
66
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
67
                                        buffer.WriteString(fmt.Sprintf("RequstTime:%v \n", time.Now().Format(constant.StdTimeLayout)))
68
                                        buffer.WriteString(fmt.Sprintf("Hostname:%v \n", hostname))
69
                                        buffer.WriteString(fmt.Sprintf("TraceID:%v \n", c.GetString(fusCtx.KeyTraceID)))
70
                                        buffer.WriteString(fmt.Sprintf("RequestURI:%v \n",
71
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
72
                                        buffer.WriteString(fmt.Sprintf("UA:%v \n", c.Request.UserAgent()))
73
                                        buffer.WriteString(fmt.Sprintf("IP:%v \n", c.ClientIP()))
74
                                        buffer.WriteString(fmt.Sprintf("ErrorStack:\n%v", debugStack))
75
                                }
76
77
                                if logger != nil {
78
                                        logger.Errorf(buffer.String(), fusCtx.New(fusCtx.Gin(c)))
79
                                } else {
80
                                        log.Printf(buffer.String())
81
                                }
82
83
                                c.AbortWithStatusJSON(http.StatusInternalServerError, map[string]any{
84
                                        "code":    http.StatusInternalServerError,
85
                                        "message": "service internal error",
86
                                })
87
                        }
88
                }()
89
                c.Next()
90
        }
91
}
func @26:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/recover.go:

26
func(c *gin.Context) {
27
                defer func() {
28
                        if err := recover(); err != nil {
29
                                // Check for a broken connection, as it is not really a
30
                                // condition that warrants a panic stack trace.
31
                                var brokenPipe bool
32
                                if ne, ok := err.(*net.OpError); ok {
33
                                        if se, ok := ne.Err.(*os.SyscallError); ok {
34
                                                if strings.Contains(strings.ToLower(se.Error()), "broken pipe") ||
35
                                                        strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
36
                                                        brokenPipe = true
37
                                                }
38
                                        }
39
                                }
40
                                if brokenPipe {
41
                                        c.Abort()
42
                                        return
43
                                }
44
                                debugStack := ""
45
                                for _, v := range strings.Split(string(debug.Stack()), "\n") {
46
                                        debugStack += "> " + v + "\n"
47
                                }
48
                                hostname, hostnameErr := os.Hostname()
49
                                if hostnameErr != nil {
50
                                        hostname = "unknown"
51
                                }
52
                                buffer, cb := utils.BytesBufferPool.Get(nil)
53
                                defer cb()
54
55
                                if tag == language.Chinese {
56
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
57
                                        buffer.WriteString(fmt.Sprintf("请求时间:%v \n", time.Now().Format(constant.StdTimeLayout)))
58
                                        buffer.WriteString(fmt.Sprintf("主机名称:%v \n", hostname))
59
                                        buffer.WriteString(fmt.Sprintf("请求编号:%v \n", c.GetString(fusCtx.KeyTraceID)))
60
                                        buffer.WriteString(fmt.Sprintf("请求地址:%v \n",
61
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
62
                                        buffer.WriteString(fmt.Sprintf("请求UA:%v \n", c.Request.UserAgent()))
63
                                        buffer.WriteString(fmt.Sprintf("请求IP:%v \n", c.ClientIP()))
64
                                        buffer.WriteString(fmt.Sprintf("异常捕获:\n%v", debugStack))
65
                                } else {
66
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
67
                                        buffer.WriteString(fmt.Sprintf("RequstTime:%v \n", time.Now().Format(constant.StdTimeLayout)))
68
                                        buffer.WriteString(fmt.Sprintf("Hostname:%v \n", hostname))
69
                                        buffer.WriteString(fmt.Sprintf("TraceID:%v \n", c.GetString(fusCtx.KeyTraceID)))
70
                                        buffer.WriteString(fmt.Sprintf("RequestURI:%v \n",
71
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
72
                                        buffer.WriteString(fmt.Sprintf("UA:%v \n", c.Request.UserAgent()))
73
                                        buffer.WriteString(fmt.Sprintf("IP:%v \n", c.ClientIP()))
74
                                        buffer.WriteString(fmt.Sprintf("ErrorStack:\n%v", debugStack))
75
                                }
76
77
                                if logger != nil {
78
                                        logger.Errorf(buffer.String(), fusCtx.New(fusCtx.Gin(c)))
79
                                } else {
80
                                        log.Printf(buffer.String())
81
                                }
82
83
                                c.AbortWithStatusJSON(http.StatusInternalServerError, map[string]any{
84
                                        "code":    http.StatusInternalServerError,
85
                                        "message": "service internal error",
86
                                })
87
                        }
88
                }()
89
                c.Next()
90
        }
func @30:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

30
func() bool {
31
                                userID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "user_id")
32
                                return userID != ""
33
                        }
func @17:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

17
func() bool { traceID = c.GetHeader(fusCtx.KeyTraceID); return traceID != "" }
func XSS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

17
func XSS(whitelistURLs []string) gin.HandlerFunc {
18
        // Do this once for each unique policy, and use the policy for the life of the
19
        // program Policy creation/editing is not safe to use in multiple goroutines.
20
        p := bluemonday.UGCPolicy()
21
22
        return func(c *gin.Context) {
23
                for _, u := range whitelistURLs {
24
                        if strings.HasPrefix(c.Request.URL.String(), u) {
25
                                c.Next()
26
                                return
27
                        }
28
                }
29
30
                sanitizedQuery, err := xssFilterQuery(p, c.Request.URL.RawQuery)
31
                if err != nil {
32
                        err = errors.Wrap(err, "filter query")
33
                        _ = c.Error(err)
34
                        c.Abort()
35
                        return
36
                }
37
                c.Request.URL.RawQuery = sanitizedQuery
38
39
                var sanitizedBody string
40
                body, err := c.GetRawData()
41
                if err != nil {
42
                        err = errors.Wrap(err, "read body")
43
                        _ = c.Error(err)
44
                        c.Abort()
45
                        return
46
                }
47
48
                // xssFilterJSON() will return error when body is empty.
49
                if len(body) == 0 {
50
                        c.Next()
51
                        return
52
                }
53
54
                switch binding.Default(c.Request.Method, c.ContentType()) {
55
                case binding.JSON:
56
                        if sanitizedBody, err = xssFilterJSON(p, string(body)); err != nil {
57
                                err = errors.Wrap(err, "filter json")
58
                        }
59
                case binding.FormMultipart:
60
                        sanitizedBody = xssFilterPlain(p, string(body))
61
                case binding.Form:
62
                        if sanitizedBody, err = xssFilterQuery(p, string(body)); err != nil {
63
                                err = errors.Wrap(err, "filter form")
64
                        }
65
                }
66
                if err != nil {
67
                        _ = c.Error(err)
68
                        c.Abort()
69
                        return
70
                }
71
72
                c.Request.Body = ioutil.NopCloser(strings.NewReader(sanitizedBody))
73
                c.Next()
74
        }
75
}
func @23:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

23
func() bool { traceID = utils.NginxID(); return traceID != "" }
func Trace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/trace.go:

11
func Trace() gin.HandlerFunc {
12
        return func(c *gin.Context) {
13
                var (
14
                        userID, traceID string
15
                )
16
                utils.IfAny(
17
                        func() bool { traceID = c.GetHeader(fusCtx.KeyTraceID); return traceID != "" },
18
                        func() bool { traceID = c.GetHeader("HTTP_TRACE_ID"); return traceID != "" },
19
                        func() bool {
20
                                traceID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "trace_id")
21
                                return traceID != ""
22
                        },
23
                        func() bool { traceID = utils.NginxID(); return traceID != "" },
24
                )
25
                c.Header("Trace-Id", traceID)
26
                c.Set(fusCtx.KeyTraceID, traceID)
27
28
                utils.IfAny(
29
                        func() bool { userID = c.GetHeader(fusCtx.KeyUserID); return userID != "" },
30
                        func() bool {
31
                                userID = utils.LookupByFuzzyKeyword[string](c.GetHeader, "user_id")
32
                                return userID != ""
33
                        },
34
                        func() bool {
35
                                userID = utils.LookupByFuzzyKeyword[string](c.GetQuery, "user_id")
36
                                return userID != ""
37
                        },
38
                        func() bool {
39
                                userID = utils.LookupByFuzzyKeyword[string](c.GetPostForm, "user_id")
40
                                return userID != ""
41
                        },
42
                )
43
                c.Set(fusCtx.KeyUserID, userID)
44
                c.Next()
45
        }
46
}
func Logging
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/logging.go:

119
func Logging(ctx context.Context, appName string, logger resty.Logger) gin.HandlerFunc {
120
        return func(c *gin.Context) {
121
                reqURL := clone.Clone(c.Request.URL)
122
                defer logging(ctx, c, logger, reqURL, appName)
123
124
                c.Next()
125
        }
126
127
}
func Gateway
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/gateway.go:

9
func Gateway(c *gin.Context) {
10
        consts.SetReqStartTime(c)
11
}
func Cors
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/cors.go:

11
func Cors() gin.HandlerFunc {
12
        return func(c *gin.Context) {
13
                origin := c.Request.Header.Get("Origin")
14
                var headerKeys []string
15
                for k := range c.Request.Header {
16
                        headerKeys = append(headerKeys, k)
17
                }
18
                corsHeader := c.GetHeader("Access-Control-Request-Headers")
19
                headerKeys = append(headerKeys, strings.Split(corsHeader, ",")...)
20
21
                headerStr := strings.Join(headerKeys, ", ")
22
                if headerStr != "" {
23
                        headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
24
                } else {
25
                        headerStr = "access-control-allow-origin, access-control-allow-headers"
26
                }
27
                if origin != "" {
28
                        c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
29
                        c.Writer.Header().Set("Access-Control-Allow-Headers", headerStr)
30
                        c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
31
                        c.Writer.Header().Set("Access-Control-Expose-Headers",
32
                                "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
33
                        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
34
                }
35
36
                if c.Request.Method == "OPTIONS" {
37
                        c.AbortWithStatusJSON(http.StatusNoContent, "no content")
38
                }
39
                c.Next()
40
        }
41
}
func metricsLogging
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/logging.go:

82
func metricsLogging(ctx context.Context, appName, path, method string,
83
        status, rspSize int, reqSize int64, cost float64) {
84
        select {
85
        case <-ctx.Done():
86
                return
87
        default:
88
89
        }
90
91
        labels := []metrics.Label{
92
                {Key: "path", Value: path},
93
                {Key: "method", Value: method},
94
                {Key: "status", Value: cast.ToString(status)},
95
                {Key: "req_size", Value: cast.ToString(reqSize)},
96
                {Key: "rsp_size", Value: cast.ToString(rspSize)},
97
        }
98
        app := config.Use(appName).AppName()
99
        latencyKey := append([]string{app}, metricsLatencyKey...)
100
        totalKey := append([]string{app}, metricsTotalKey...)
101
        for _, m := range metrics.Internal(metrics.AppName(appName)) {
102
                select {
103
                case <-ctx.Done():
104
                        return
105
                default:
106
                        if m.IsEnableServiceLabel() {
107
                                m.IncrCounter(ctx, totalKey, 1, metrics.Labels(labels))
108
                                m.AddSample(ctx, latencyKey, cost, metrics.Labels(labels),
109
                                        metrics.PrometheusBuckets(metricsLatencyBuckets))
110
                        } else {
111
                                m.IncrCounter(ctx, metricsTotalKey, 1, metrics.Labels(labels))
112
                                m.AddSample(ctx, metricsLatencyKey, cost, metrics.Labels(labels),
113
                                        metrics.PrometheusBuckets(metricsLatencyBuckets))
114
                        }
115
                }
116
        }
117
}
func logging
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/logging.go:

37
func logging(rootCtx context.Context, c *gin.Context, logger resty.Logger, rawURL *url.URL, appName string) {
38
        ctx := fusCtx.New(fusCtx.Gin(c))
39
        cost := float64(consts.GetReqCost(c)) / float64(time.Millisecond)
40
        status := c.Writer.Status()
41
        fields := fusLog.Fields{
42
                "path":        rawURL.Path,
43
                "method":      c.Request.Method,
44
                "status":      status,
45
                "referer":     c.Request.Referer(),
46
                "req_size":    c.Request.ContentLength,
47
                "rsp_size":    c.Writer.Size(),
48
                "cost":        cost,
49
                "user_agent":  c.Request.UserAgent(),
50
                "client_addr": c.ClientIP(),
51
        }
52
53
        // skip health check logging
54
        if rawURL.Path == "/health" && c.Request.Method == http.MethodGet {
55
                return
56
        }
57
58
        msg := fmt.Sprintf(
59
                "%s -> %s %s %d %d %d (%.2fms)",
60
                c.ClientIP(), utils.LocalIP.String(),
61
                strconv.Quote(fmt.Sprintf("%s %s", c.Request.Method, rawURL)),
62
                c.Request.ContentLength, c.Writer.Size(), status, cost,
63
        )
64
65
        if logger != nil {
66
                switch {
67
                case status < http.StatusBadRequest:
68
                        logger.Debugf(msg, ctx, fields)
69
                case status >= http.StatusBadRequest && status < http.StatusInternalServerError:
70
                        logger.Warnf(msg, ctx, fields)
71
                default:
72
                        logger.Errorf(msg, ctx, fields)
73
                }
74
        } else {
75
                log.Printf(msg+" %s", utils.MustJsonMarshal(fields))
76
        }
77
78
        go metricsLogging(rootCtx, appName, rawURL.Path, c.Request.Method, status,
79
                c.Writer.Size(), c.Request.ContentLength, cost)
80
}
func @12:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/cors.go:

12
func(c *gin.Context) {
13
                origin := c.Request.Header.Get("Origin")
14
                var headerKeys []string
15
                for k := range c.Request.Header {
16
                        headerKeys = append(headerKeys, k)
17
                }
18
                corsHeader := c.GetHeader("Access-Control-Request-Headers")
19
                headerKeys = append(headerKeys, strings.Split(corsHeader, ",")...)
20
21
                headerStr := strings.Join(headerKeys, ", ")
22
                if headerStr != "" {
23
                        headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
24
                } else {
25
                        headerStr = "access-control-allow-origin, access-control-allow-headers"
26
                }
27
                if origin != "" {
28
                        c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
29
                        c.Writer.Header().Set("Access-Control-Allow-Headers", headerStr)
30
                        c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
31
                        c.Writer.Header().Set("Access-Control-Expose-Headers",
32
                                "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
33
                        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
34
                }
35
36
                if c.Request.Method == "OPTIONS" {
37
                        c.AbortWithStatusJSON(http.StatusNoContent, "no content")
38
                }
39
                c.Next()
40
        }
func @27:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/recover.go:

27
func() {
28
                        if err := recover(); err != nil {
29
                                // Check for a broken connection, as it is not really a
30
                                // condition that warrants a panic stack trace.
31
                                var brokenPipe bool
32
                                if ne, ok := err.(*net.OpError); ok {
33
                                        if se, ok := ne.Err.(*os.SyscallError); ok {
34
                                                if strings.Contains(strings.ToLower(se.Error()), "broken pipe") ||
35
                                                        strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
36
                                                        brokenPipe = true
37
                                                }
38
                                        }
39
                                }
40
                                if brokenPipe {
41
                                        c.Abort()
42
                                        return
43
                                }
44
                                debugStack := ""
45
                                for _, v := range strings.Split(string(debug.Stack()), "\n") {
46
                                        debugStack += "> " + v + "\n"
47
                                }
48
                                hostname, hostnameErr := os.Hostname()
49
                                if hostnameErr != nil {
50
                                        hostname = "unknown"
51
                                }
52
                                buffer, cb := utils.BytesBufferPool.Get(nil)
53
                                defer cb()
54
55
                                if tag == language.Chinese {
56
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
57
                                        buffer.WriteString(fmt.Sprintf("请求时间:%v \n", time.Now().Format(constant.StdTimeLayout)))
58
                                        buffer.WriteString(fmt.Sprintf("主机名称:%v \n", hostname))
59
                                        buffer.WriteString(fmt.Sprintf("请求编号:%v \n", c.GetString(fusCtx.KeyTraceID)))
60
                                        buffer.WriteString(fmt.Sprintf("请求地址:%v \n",
61
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
62
                                        buffer.WriteString(fmt.Sprintf("请求UA:%v \n", c.Request.UserAgent()))
63
                                        buffer.WriteString(fmt.Sprintf("请求IP:%v \n", c.ClientIP()))
64
                                        buffer.WriteString(fmt.Sprintf("异常捕获:\n%v", debugStack))
65
                                } else {
66
                                        buffer.WriteString(fmt.Sprintf("%v \n", err))
67
                                        buffer.WriteString(fmt.Sprintf("RequstTime:%v \n", time.Now().Format(constant.StdTimeLayout)))
68
                                        buffer.WriteString(fmt.Sprintf("Hostname:%v \n", hostname))
69
                                        buffer.WriteString(fmt.Sprintf("TraceID:%v \n", c.GetString(fusCtx.KeyTraceID)))
70
                                        buffer.WriteString(fmt.Sprintf("RequestURI:%v \n",
71
                                                c.Request.Method+"  "+c.Request.Host+c.Request.RequestURI))
72
                                        buffer.WriteString(fmt.Sprintf("UA:%v \n", c.Request.UserAgent()))
73
                                        buffer.WriteString(fmt.Sprintf("IP:%v \n", c.ClientIP()))
74
                                        buffer.WriteString(fmt.Sprintf("ErrorStack:\n%v", debugStack))
75
                                }
76
77
                                if logger != nil {
78
                                        logger.Errorf(buffer.String(), fusCtx.New(fusCtx.Gin(c)))
79
                                } else {
80
                                        log.Printf(buffer.String())
81
                                }
82
83
                                c.AbortWithStatusJSON(http.StatusInternalServerError, map[string]any{
84
                                        "code":    http.StatusInternalServerError,
85
                                        "message": "service internal error",
86
                                })
87
                        }
88
                }
func @22:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

22
func(c *gin.Context) {
23
                for _, u := range whitelistURLs {
24
                        if strings.HasPrefix(c.Request.URL.String(), u) {
25
                                c.Next()
26
                                return
27
                        }
28
                }
29
30
                sanitizedQuery, err := xssFilterQuery(p, c.Request.URL.RawQuery)
31
                if err != nil {
32
                        err = errors.Wrap(err, "filter query")
33
                        _ = c.Error(err)
34
                        c.Abort()
35
                        return
36
                }
37
                c.Request.URL.RawQuery = sanitizedQuery
38
39
                var sanitizedBody string
40
                body, err := c.GetRawData()
41
                if err != nil {
42
                        err = errors.Wrap(err, "read body")
43
                        _ = c.Error(err)
44
                        c.Abort()
45
                        return
46
                }
47
48
                // xssFilterJSON() will return error when body is empty.
49
                if len(body) == 0 {
50
                        c.Next()
51
                        return
52
                }
53
54
                switch binding.Default(c.Request.Method, c.ContentType()) {
55
                case binding.JSON:
56
                        if sanitizedBody, err = xssFilterJSON(p, string(body)); err != nil {
57
                                err = errors.Wrap(err, "filter json")
58
                        }
59
                case binding.FormMultipart:
60
                        sanitizedBody = xssFilterPlain(p, string(body))
61
                case binding.Form:
62
                        if sanitizedBody, err = xssFilterQuery(p, string(body)); err != nil {
63
                                err = errors.Wrap(err, "filter form")
64
                        }
65
                }
66
                if err != nil {
67
                        _ = c.Error(err)
68
                        c.Abort()
69
                        return
70
                }
71
72
                c.Request.Body = ioutil.NopCloser(strings.NewReader(sanitizedBody))
73
                c.Next()
74
        }
func xssFilterJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

93
func xssFilterJSON(p *bluemonday.Policy, s string) (string, error) {
94
        var data any
95
        if err := json.Unmarshal([]byte(s), &data); err != nil {
96
                return "", err
97
        }
98
99
        b := strings.Builder{}
100
        e := json.NewEncoder(&b)
101
        e.SetEscapeHTML(false)
102
        if err := e.Encode(xssFilterJSONData(p, data)); err != nil {
103
                return "", err
104
        }
105
        // use `TrimSpace` to trim newline char add by `Encode`.
106
        return strings.TrimSpace(b.String()), nil
107
}
func xssFilterJSONData
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

109
func xssFilterJSONData(p *bluemonday.Policy, d any) any {
110
        switch data := d.(type) {
111
        case []any:
112
                for i, v := range data {
113
                        data[i] = xssFilterJSONData(p, v)
114
                }
115
                return data
116
        case map[string]any:
117
                for k, v := range data {
118
                        data[k] = xssFilterJSONData(p, v)
119
                }
120
                return data
121
        case string:
122
                return xssFilterPlain(p, data)
123
        default:
124
                return data
125
        }
126
}
func xssFilterQuery
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

77
func xssFilterQuery(p *bluemonday.Policy, s string) (string, error) {
78
        values, err := url.ParseQuery(s)
79
        if err != nil {
80
                return "", err
81
        }
82
83
        for k, v := range values {
84
                values.Del(k)
85
                for _, vv := range v {
86
                        values.Add(k, xssFilterPlain(p, vv))
87
                }
88
        }
89
90
        return values.Encode(), nil
91
}
func xssFilterPlain
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/middleware/xss.go:

128
func xssFilterPlain(p *bluemonday.Policy, s string) string {
129
        sanitized := p.Sanitize(s)
130
        return html.UnescapeString(sanitized)
131
}
Package Overview: github.com/wfusion/gofusion/http/parser 47.4%

Please select a function to see what's left for testing.

MapFormByTag(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 100.0% 10/10
mappingByPtr(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 100.0% 2/2
ApplicationFormUrlencodedParser.PreParse(...) github.com/wfusion/gofusion/http/parser/application_x_www_form_urlencoded.go 100.0% 1/1
formSource.TrySet(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 100.0% 1/1
MultipartFormDataParser.transformField(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 92.3% 12/13
mapping(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 85.3% 29/34
setSlice(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 83.3% 5/6
setIntField(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 83.3% 5/6
MultipartFormDataParser.lookupFieldByTag(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 83.3% 5/6
setArray(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 80.0% 4/5
MultipartFormDataParser.PreParse(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 80.0% 4/5
GetByContentType(...) github.com/wfusion/gofusion/http/parser/parser.go 75.0% 3/4
head(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 75.0% 3/4
tryToSetValue(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 73.3% 11/15
MultipartFormDataParser.Parse(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 72.0% 18/25
ApplicationFormUrlencodedParser.Parse(...) github.com/wfusion/gofusion/http/parser/application_x_www_form_urlencoded.go 71.4% 5/7
setByForm(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 61.1% 11/18
setFormMap(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 58.8% 10/17
@48:8(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 50.0% 1/2
setWithProperType(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 17.4% 4/23
setTimeField(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 0.0% 0/29
setFloatField(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 0.0% 0/6
setBoolField(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 0.0% 0/6
setUintField(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 0.0% 0/6
setTimeDuration(...) github.com/wfusion/gofusion/http/parser/form_mapping.go 0.0% 0/5
@105:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@100:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@101:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@102:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@103:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@104:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@99:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@106:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@107:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@108:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@109:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@110:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
ApplicationJsonParser.Parse(...) github.com/wfusion/gofusion/http/parser/application_json.go 0.0% 0/3
@112:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
@111:20(...) github.com/wfusion/gofusion/http/parser/multipart_formdata.go 0.0% 0/3
ApplicationJsonParser.PreParse(...) github.com/wfusion/gofusion/http/parser/application_json.go 0.0% 0/1
malformedRequest(...) github.com/wfusion/gofusion/http/parser/parser.go 0.0% 0/1
unsupportedContentType(...) github.com/wfusion/gofusion/http/parser/parser.go 0.0% 0/1
func MapFormByTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

28
func MapFormByTag(ptr any, form map[string][]string, tag string) error {
29
        // Check if ptr is a map
30
        ptrVal := reflect.ValueOf(ptr)
31
        var pointed any
32
        if ptrVal.Kind() == reflect.Ptr {
33
                ptrVal = ptrVal.Elem()
34
                pointed = ptr
35
        }
36
        if ptrVal.Type() == mapStringInterfaceSliceType ||
37
                (ptrVal.Kind() == reflect.Map && ptrVal.Type().Key().Kind() == reflect.String) {
38
                if pointed != nil {
39
                        ptr = pointed
40
                }
41
                return setFormMap(ptr, form)
42
        }
43
44
        return mappingByPtr(ptr, formSource(form), tag)
45
}
func mappingByPtr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

62
func mappingByPtr(ptr any, setter setter, tag string) error {
63
        _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
64
        return err
65
}
func ApplicationFormUrlencodedParser.PreParse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/application_x_www_form_urlencoded.go:

11
func (a *ApplicationFormUrlencodedParser) PreParse(args map[string]string) error {
12
        return nil
13
}
func formSource.TrySet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

57
func (form formSource) TrySet(value reflect.Value, field reflect.StructField,
58
        tagValue string, opt setOptions) (isSetted bool, err error) {
59
        return setByForm(value, field, form, tagValue, opt)
60
}
func MultipartFormDataParser.transformField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

116
func (m *MultipartFormDataParser) transformField(f reflect.Value, param []byte) (err error) {
117
        ft := f.Type()
118
        if ft.Kind() == reflect.Ptr {
119
                ft = ft.Elem()
120
                if f.IsNil() {
121
                        f.Set(reflect.New(ft))
122
                }
123
                f = f.Elem()
124
        }
125
126
        if byteSliceType.ConvertibleTo(ft) {
127
                f.Set(reflect.ValueOf(param).Convert(ft))
128
                return
129
        }
130
131
        caster, ok := castReflectTypeMap[ft.Kind()]
132
        if !ok {
133
                return json.Unmarshal(param, f.Addr().Interface())
134
        }
135
136
        return caster(f, param)
137
}
func mapping
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

67
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
68
        if field.Tag.Get(tag) == "-" { // just ignoring this field
69
                return false, nil
70
        }
71
72
        var vKind = value.Kind()
73
74
        if vKind == reflect.Ptr {
75
                var isNew bool
76
                vPtr := value
77
                if value.IsNil() {
78
                        isNew = true
79
                        vPtr = reflect.New(value.Type().Elem())
80
                }
81
                isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
82
                if err != nil {
83
                        return false, err
84
                }
85
                if isNew && isSetted {
86
                        value.Set(vPtr)
87
                }
88
                return isSetted, nil
89
        }
90
91
        if vKind != reflect.Struct || !field.Anonymous {
92
                ok, err := tryToSetValue(value, field, setter, tag)
93
                if err != nil {
94
                        return false, err
95
                }
96
                if ok {
97
                        return true, nil
98
                }
99
        }
100
101
        if vKind == reflect.Struct {
102
                tValue := value.Type()
103
104
                var isSetted bool
105
                for i := 0; i < value.NumField(); i++ {
106
                        sf := tValue.Field(i)
107
                        if sf.PkgPath != "" && !sf.Anonymous { // unexported
108
                                continue
109
                        }
110
                        ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
111
                        if err != nil {
112
                                return false, err
113
                        }
114
                        isSetted = isSetted || ok
115
                }
116
                return isSetted, nil
117
        }
118
        return false, nil
119
}
func setSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

340
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
341
        slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
342
        err := setArray(vals, slice, field)
343
        if err != nil {
344
                return err
345
        }
346
        value.Set(slice)
347
        return nil
348
}
func setIntField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

235
func setIntField(val string, bitSize int, field reflect.Value) error {
236
        if val == "" {
237
                val = "0"
238
        }
239
        intVal, err := strconv.ParseInt(val, 10, bitSize)
240
        if err == nil {
241
                field.SetInt(intVal)
242
        }
243
        return err
244
}
func MultipartFormDataParser.lookupFieldByTag
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

86
func (m *MultipartFormDataParser) lookupFieldByTag(t reflect.Type, key, tag string) (fNum int) {
87
        n := t.NumField()
88
        for i := 0; i < n; i++ {
89
                f := t.Field(i)
90
                if v, ok := f.Tag.Lookup(tag); ok && v == key {
91
                        return i
92
                }
93
        }
94
        return -1
95
}
func setArray
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

330
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
331
        for i, s := range vals {
332
                err := setWithProperType(s, value.Index(i), field)
333
                if err != nil {
334
                        return err
335
                }
336
        }
337
        return nil
338
}
func MultipartFormDataParser.PreParse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

27
func (m *MultipartFormDataParser) PreParse(args map[string]string) error {
28
        boundary, ok := args[keyBoundary]
29
        if !ok {
30
                return malformedRequest("missing boundary in multipart/form-data")
31
        }
32
        m.boundary = boundary
33
        return nil
34
}
func GetByContentType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/parser.go:

32
func GetByContentType(typ string) (parser Parser, err error) {
33
        parserType, ok := parserMap[typ]
34
        if !ok {
35
                return nil, unsupportedContentType(typ)
36
        }
37
38
        return reflect.New(parserType.Elem()).Interface().(Parser), nil
39
}
func head
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

359
func head(str, sep string) (head string, tail string) {
360
        idx := strings.Index(str, sep)
361
        if idx < 0 {
362
                return str, ""
363
        }
364
        return str[:idx], str[idx+len(sep):]
365
}
func tryToSetValue
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

126
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
127
        var tagValue string
128
        var setOpt setOptions
129
130
        tagValue = field.Tag.Get(tag)
131
        tagValue, opts := head(tagValue, ",")
132
133
        if tagValue == "" { // default value is FieldName
134
                tagValue = field.Name
135
        }
136
        if tagValue == "" { // when field is "emptyField" variable
137
                return false, nil
138
        }
139
140
        var opt string
141
        for len(opts) > 0 {
142
                opt, opts = head(opts, ",")
143
144
                if k, v := head(opt, "="); k == "default" {
145
                        setOpt.isDefaultExists = true
146
                        setOpt.defaultValue = v
147
                }
148
        }
149
150
        return setter.TrySet(value, field, tagValue, setOpt)
151
}
func MultipartFormDataParser.Parse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

36
func (m *MultipartFormDataParser) Parse(src io.Reader, dst reflect.Value) (err error) {
37
        for dst.Kind() == reflect.Ptr {
38
                dst.Set(reflect.New(dst.Type().Elem()))
39
                dst = dst.Elem()
40
        }
41
42
        var (
43
                part   *multipart.Part
44
                body   []byte
45
                dt     = reflect.TypeOf(dst.Interface())
46
                reader = multipart.NewReader(src, m.boundary)
47
        )
48
        defer func() {
49
                if part != nil {
50
                        utils.CloseAnyway(part)
51
                }
52
        }()
53
54
        for {
55
                part, err = reader.NextPart()
56
                if err != nil {
57
                        if err == io.EOF {
58
                                err = nil
59
                        }
60
                        break
61
                }
62
63
                k := part.FormName()
64
                fNum := m.lookupFieldByTag(dt, k, "json")
65
                if fNum == -1 {
66
                        continue
67
                }
68
                fv := dst.Field(fNum)
69
                if !fv.IsValid() || !fv.CanSet() {
70
                        continue
71
                }
72
73
                // transform
74
                if body, err = ioutil.ReadAll(part); err != nil {
75
                        break
76
                } else if err = m.transformField(fv, body); err != nil {
77
                        break
78
                } else if err = part.Close(); err != nil {
79
                        break
80
                }
81
        }
82
83
        return
84
}
func ApplicationFormUrlencodedParser.Parse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/application_x_www_form_urlencoded.go:

15
func (a *ApplicationFormUrlencodedParser) Parse(src io.Reader, dst reflect.Value) (err error) {
16
        body, err := io.ReadAll(src)
17
        if err != nil {
18
                return
19
        }
20
21
        vals, err := url.ParseQuery(string(body))
22
        if err != nil {
23
                return
24
        }
25
26
        return MapFormByTag(dst.Addr().Interface(), vals, "json")
27
}
func setByForm
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

153
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string,
154
        tagValue string, opt setOptions) (isSetted bool, err error) {
155
        vs, ok := form[tagValue]
156
        if !ok && !opt.isDefaultExists {
157
                return false, nil
158
        }
159
160
        switch value.Kind() {
161
        case reflect.Slice:
162
                if !ok {
163
                        vs = []string{opt.defaultValue}
164
                }
165
                return true, setSlice(vs, value, field)
166
        case reflect.Array:
167
                if !ok {
168
                        vs = []string{opt.defaultValue}
169
                }
170
                if len(vs) != value.Len() {
171
                        return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
172
                }
173
                return true, setArray(vs, value, field)
174
        default:
175
                var val string
176
                if !ok {
177
                        val = opt.defaultValue
178
                }
179
180
                if len(vs) > 0 {
181
                        val = vs[0]
182
                }
183
                return true, setWithProperType(val, value, field)
184
        }
185
}
func setFormMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

367
func setFormMap(ptr any, form map[string][]string) error {
368
        switch ptrMap := ptr.(type) {
369
        case *map[string]any:
370
                *ptrMap = make(map[string]any, len(form))
371
                for k, v := range form {
372
                        (*ptrMap)[k] = v
373
                }
374
        case *[]map[string]any:
375
                *ptrMap = make([]map[string]any, 0, 1)
376
                tmp := make(map[string]any, len(form))
377
                for k, v := range form {
378
                        tmp[k] = v
379
                }
380
                *ptrMap = append(*ptrMap, tmp)
381
        case *map[string][]string:
382
                *ptrMap = make(map[string][]string, len(form))
383
                for k, v := range form {
384
                        (*ptrMap)[k] = v
385
                }
386
        case *map[string]string:
387
                *ptrMap = make(map[string]string, len(form))
388
                for k, v := range form {
389
                        (*ptrMap)[k] = v[len(v)-1] // pick last
390
                }
391
        default:
392
                return errors.New("cannot convert to map slices of strings")
393
        }
394
395
        return nil
396
}
func @48:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

48
func() {
49
                if part != nil {
50
                        utils.CloseAnyway(part)
51
                }
52
        }
func setWithProperType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

187
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
188
        switch value.Kind() {
189
        case reflect.Int:
190
                return setIntField(val, 0, value)
191
        case reflect.Int8:
192
                return setIntField(val, 8, value)
193
        case reflect.Int16:
194
                return setIntField(val, 16, value)
195
        case reflect.Int32:
196
                return setIntField(val, 32, value)
197
        case reflect.Int64:
198
                switch value.Interface().(type) {
199
                case time.Duration:
200
                        return setTimeDuration(val, value, field)
201
                }
202
                return setIntField(val, 64, value)
203
        case reflect.Uint:
204
                return setUintField(val, 0, value)
205
        case reflect.Uint8:
206
                return setUintField(val, 8, value)
207
        case reflect.Uint16:
208
                return setUintField(val, 16, value)
209
        case reflect.Uint32:
210
                return setUintField(val, 32, value)
211
        case reflect.Uint64:
212
                return setUintField(val, 64, value)
213
        case reflect.Bool:
214
                return setBoolField(val, value)
215
        case reflect.Float32:
216
                return setFloatField(val, 32, value)
217
        case reflect.Float64:
218
                return setFloatField(val, 64, value)
219
        case reflect.String:
220
                value.SetString(val)
221
        case reflect.Struct:
222
                switch value.Interface().(type) {
223
                case time.Time:
224
                        return setTimeField(val, field, value)
225
                }
226
                return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface())
227
        case reflect.Map:
228
                return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface())
229
        default:
230
                return errUnknownType
231
        }
232
        return nil
233
}
func setTimeField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

279
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
280
        timeFormat := structField.Tag.Get("time_format")
281
        if timeFormat == "" {
282
                timeFormat = time.RFC3339
283
        }
284
285
        switch tf := strings.ToLower(timeFormat); tf {
286
        case "unix", "unixnano":
287
                tv, err := strconv.ParseInt(val, 10, 64)
288
                if err != nil {
289
                        return err
290
                }
291
292
                d := time.Duration(1)
293
                if tf == "unixnano" {
294
                        d = time.Second
295
                }
296
297
                t := time.Unix(tv/int64(d), tv%int64(d))
298
                value.Set(reflect.ValueOf(t))
299
                return nil
300
301
        }
302
303
        if val == "" {
304
                value.Set(reflect.ValueOf(time.Time{}))
305
                return nil
306
        }
307
308
        l := time.Local
309
        if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
310
                l = time.UTC
311
        }
312
313
        if locTag := structField.Tag.Get("time_location"); locTag != "" {
314
                loc, err := time.LoadLocation(locTag)
315
                if err != nil {
316
                        return err
317
                }
318
                l = loc
319
        }
320
321
        t, err := time.ParseInLocation(timeFormat, val, l)
322
        if err != nil {
323
                return err
324
        }
325
326
        value.Set(reflect.ValueOf(t))
327
        return nil
328
}
func setFloatField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

268
func setFloatField(val string, bitSize int, field reflect.Value) error {
269
        if val == "" {
270
                val = "0.0"
271
        }
272
        floatVal, err := strconv.ParseFloat(val, bitSize)
273
        if err == nil {
274
                field.SetFloat(floatVal)
275
        }
276
        return err
277
}
func setBoolField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

257
func setBoolField(val string, field reflect.Value) error {
258
        if val == "" {
259
                val = "false"
260
        }
261
        boolVal, err := strconv.ParseBool(val)
262
        if err == nil {
263
                field.SetBool(boolVal)
264
        }
265
        return err
266
}
func setUintField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

246
func setUintField(val string, bitSize int, field reflect.Value) error {
247
        if val == "" {
248
                val = "0"
249
        }
250
        uintVal, err := strconv.ParseUint(val, 10, bitSize)
251
        if err == nil {
252
                field.SetUint(uintVal)
253
        }
254
        return err
255
}
func setTimeDuration
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/form_mapping.go:

350
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
351
        d, err := time.ParseDuration(val)
352
        if err != nil {
353
                return err
354
        }
355
        value.Set(reflect.ValueOf(d))
356
        return nil
357
}
func @105:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

105
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return }
func @100:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

100
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToStringE(b); f.SetString(v); return }
func @101:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

101
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return }
func @102:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

102
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return }
func @103:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

103
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return }
func @104:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

104
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToInt64E(b); f.SetInt(v); return }
func @99:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

99
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToBoolE(b); f.SetBool(v); return }
func @106:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

106
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return }
func @107:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

107
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return }
func @108:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

108
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return }
func @109:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

109
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return }
func @110:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

110
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToUint64E(b); f.SetUint(v); return }
func ApplicationJsonParser.Parse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/application_json.go:

16
func (a *ApplicationJsonParser) Parse(src io.Reader, dst reflect.Value) (err error) {
17
        if err = json.NewDecoder(src).Decode(dst.Addr().Interface()); err != nil {
18
                return malformedRequest(err.Error())
19
        }
20
21
        return
22
}
func @112:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

112
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToFloat64E(b); f.SetFloat(v); return }
func @111:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/multipart_formdata.go:

111
func(f reflect.Value, b []byte) (e error) { v, e := cast.ToFloat64E(b); f.SetFloat(v); return }
func ApplicationJsonParser.PreParse
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/application_json.go:

12
func (a *ApplicationJsonParser) PreParse(args map[string]string) error {
13
        return nil
14
}
func malformedRequest
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/parser.go:

16
func malformedRequest(msg string) error {
17
        return fmt.Errorf("malformed request %s", msg)
18
}
func unsupportedContentType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/http/parser/parser.go:

20
func unsupportedContentType(typ string) error {
21
        return fmt.Errorf("unsupported content-type %s", typ)
22
}
Package Overview: github.com/wfusion/gofusion/i18n 57.0%

Please select a function to see what's left for testing.

bundle[T].AddMessages(...) github.com/wfusion/gofusion/i18n/i18n.go 100.0% 9/9
NewBundle(...) github.com/wfusion/gofusion/i18n/i18n.go 100.0% 6/6
DefaultLang(...) github.com/wfusion/gofusion/i18n/construct.go 100.0% 4/4
@51:9(...) github.com/wfusion/gofusion/i18n/construct.go 100.0% 3/3
AppName(...) github.com/wfusion/gofusion/i18n/construct.go 100.0% 1/1
@66:9(...) github.com/wfusion/gofusion/i18n/construct.go 100.0% 1/1
Var(...) github.com/wfusion/gofusion/i18n/i18n.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/i18n/construct.go 100.0% 1/1
@57:9(...) github.com/wfusion/gofusion/i18n/i18n.go 100.0% 1/1
Construct(...) github.com/wfusion/gofusion/i18n/construct.go 95.0% 19/20
bundle[T].checkDuplicated(...) github.com/wfusion/gofusion/i18n/i18n.go 27.3% 3/11
bundle[T].Localize(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/16
@142:9(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/3
@48:16(...) github.com/wfusion/gofusion/i18n/construct.go 0.0% 0/1
@47:16(...) github.com/wfusion/gofusion/i18n/construct.go 0.0% 0/1
Param(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
@130:9(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
Lang(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
@136:9(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
Langs(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
@124:9(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
Plural(...) github.com/wfusion/gofusion/i18n/i18n.go 0.0% 0/1
func bundle[T].AddMessages
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

62
func (i *bundle[T]) AddMessages(code T, trans map[language.Tag]*Message, opts ...utils.OptionExtender) Localizable[T] {
63
        o := utils.ApplyOptions[addMessagesOption](opts...)
64
65
        i.mutex.Lock()
66
        defer i.mutex.Unlock()
67
        i.checkDuplicated(code, trans)
68
69
        id := cast.ToString(code)
70
        i.vars[code] = o.vars
71
        for lang, msg := range trans {
72
                i.bundle.MustAddMessages(lang, &i18n.Message{
73
                        ID:          id,
74
                        Hash:        msg.Hash,
75
                        Description: msg.Description,
76
                        LeftDelim:   msg.LeftDelim,
77
                        RightDelim:  msg.RightDelim,
78
                        Zero:        msg.Zero,
79
                        One:         msg.One,
80
                        Two:         msg.Two,
81
                        Few:         msg.Few,
82
                        Many:        msg.Many,
83
                        Other:       msg.Other,
84
                })
85
        }
86
        return i
87
}
func NewBundle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

37
func NewBundle[T comparable](lang language.Tag) Localizable[T] {
38
        b := &bundle[T]{
39
                dup:    utils.NewSet[T](),
40
                bundle: i18n.NewBundle(lang),
41
                vars:   make(map[T][]string),
42
        }
43
44
        b.bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
45
        b.bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
46
        b.bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
47
        b.bundle.RegisterUnmarshalFunc("yml", yaml.Unmarshal)
48
49
        return b
50
}
func DefaultLang
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

71
func DefaultLang(opts ...utils.OptionExtender) (lang language.Tag) {
72
        opt := utils.ApplyOptions[useOption](opts...)
73
74
        conf := new(Conf)
75
        utils.MustSuccess(config.Use(opt.appName).LoadComponentConfig(config.ComponentI18n, conf))
76
        return utils.Must(language.Parse(conf.DefaultLang))
77
}
func @51:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

51
func() {
52
                locker.Lock()
53
                defer locker.Unlock()
54
                Bundle = &bundle[int]{
55
                        dup:    utils.NewSet[int](),
56
                        bundle: i18n.NewBundle(lang),
57
                }
58
        }
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

65
func AppName(name string) utils.OptionFunc[useOption] {
66
        return func(o *useOption) {
67
                o.appName = name
68
        }
69
}
func @66:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

66
func(o *useOption) {
67
                o.appName = name
68
        }
func Var
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

56
func Var(vars ...string) utils.OptionFunc[addMessagesOption] {
57
        return func(o *addMessagesOption) {
58
                o.vars = vars
59
        }
60
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

79
func init() {
80
        config.AddComponent(config.ComponentI18n, Construct)
81
}
func @57:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

57
func(o *addMessagesOption) {
58
                o.vars = vars
59
        }
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

16
func Construct(ctx context.Context, conf Conf, opts ...utils.OptionExtender) func() {
17
        var err error
18
        lang := defaultLang
19
        if utils.IsStrNotBlank(conf.DefaultLang) {
20
                if lang, err = language.Parse(conf.DefaultLang); err != nil {
21
                        panic(err)
22
                }
23
        }
24
25
        opt := utils.ApplyOptions[config.InitOption](opts...)
26
        optU := utils.ApplyOptions[useOption](opts...)
27
        if opt.AppName == "" {
28
                opt.AppName = optU.appName
29
        }
30
31
        locker.Lock()
32
        defer locker.Unlock()
33
        if Bundle == nil {
34
                Bundle = &bundle[int]{
35
                        dup:    utils.NewSet[int](),
36
                        bundle: i18n.NewBundle(lang),
37
                }
38
                Bundle.bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
39
                Bundle.bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
40
                Bundle.bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
41
                Bundle.bundle.RegisterUnmarshalFunc("yml", yaml.Unmarshal)
42
        }
43
44
        // ioc
45
        if opt.DI != nil {
46
                opt.DI.
47
                        MustProvide(func() Localizable[int] { return NewBundle[int](lang) }).
48
                        MustProvide(func() Localizable[string] { return NewBundle[string](lang) })
49
        }
50
51
        return func() {
52
                locker.Lock()
53
                defer locker.Unlock()
54
                Bundle = &bundle[int]{
55
                        dup:    utils.NewSet[int](),
56
                        bundle: i18n.NewBundle(lang),
57
                }
58
        }
59
}
func bundle[T].checkDuplicated
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

89
func (i *bundle[T]) checkDuplicated(code T, trans map[language.Tag]*Message) {
90
        if !i.dup.Contains(code) {
91
                i.dup.Insert(code)
92
                return
93
        }
94
        if trans == nil {
95
                panic(errors.Errorf("%+v %s code translation is empty", code, cast.ToString(code)))
96
        }
97
98
        // panic if duplicated
99
        var (
100
                cfg                = &i18n.LocalizeConfig{MessageID: cast.ToString(code)}
101
                existMsgEn         = i18n.NewLocalizer(i.bundle, language.English.String()).MustLocalize(cfg)
102
                existMsgCn         = i18n.NewLocalizer(i.bundle, language.Chinese.String()).MustLocalize(cfg)
103
                dupMsgCn, dupMsgEn string
104
        )
105
        if dupMsg, ok := trans[language.Chinese]; ok {
106
                dupMsgCn = dupMsg.Other
107
        }
108
        if dupMsg, ok := trans[language.English]; ok {
109
                dupMsgEn = dupMsg.Other
110
        }
111
112
        panic(errors.Errorf("%s(%s)(%+v)(%v) is duplicated with %s(%s)",
113
                dupMsgCn, dupMsgEn, code, cast.ToString(code), existMsgCn, existMsgEn))
114
}
func bundle[T].Localize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

150
func (i *bundle[T]) Localize(code T, opts ...utils.OptionExtender) (message string) {
151
        option := utils.ApplyOptions[localizeOption](opts...)
152
        if option.templateData == nil && len(i.vars) > 0 {
153
                option.templateData = make(map[string]any, len(i.vars))
154
        }
155
156
        // TODO: Access the third-party internationalization platform to obtain text
157
        cfg := &i18n.LocalizeConfig{
158
                MessageID:    cast.ToString(code),
159
                TemplateData: option.templateData,
160
                PluralCount:  option.pluralCount,
161
        }
162
163
        i.mutex.RLock()
164
        defer i.mutex.RUnlock()
165
        // Assign an empty string to a variable to avoid rendering < no value > data
166
        for _, v := range i.vars[code] {
167
                if _, ok := option.templateData[v]; !ok {
168
                        option.templateData[v] = ""
169
                }
170
        }
171
        message, err := i18n.NewLocalizer(i.bundle, option.langs...).Localize(cfg)
172
        if err == nil {
173
                return
174
        }
175
        message, ok := defaultErrorMessages[option.lang]
176
        if ok {
177
                return
178
        }
179
180
        return defaultErrorMessages[defaultLang]
181
}
func @142:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

142
func(o *localizeOption) {
143
                if len(langs) > 0 {
144
                        o.lang, _ = language.Parse(langs[0])
145
                }
146
                o.langs = clone.SliceComparable(langs)
147
        }
func @48:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

48
func() Localizable[string] { return NewBundle[string](lang) }
func @47:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/construct.go:

47
func() Localizable[int] { return NewBundle[int](lang) }
func Param
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

123
func Param(data map[string]any) utils.OptionFunc[localizeOption] {
124
        return func(o *localizeOption) {
125
                o.templateData = data
126
        }
127
}
func @130:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

130
func(o *localizeOption) {
131
                o.pluralCount = pluralCount
132
        }
func Lang
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

135
func Lang(lang language.Tag) utils.OptionFunc[localizeOption] {
136
        return func(o *localizeOption) {
137
                o.lang = lang
138
        }
139
}
func @136:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

136
func(o *localizeOption) {
137
                o.lang = lang
138
        }
func Langs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

141
func Langs(langs []string) utils.OptionFunc[localizeOption] {
142
        return func(o *localizeOption) {
143
                if len(langs) > 0 {
144
                        o.lang, _ = language.Parse(langs[0])
145
                }
146
                o.langs = clone.SliceComparable(langs)
147
        }
148
}
func @124:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

124
func(o *localizeOption) {
125
                o.templateData = data
126
        }
func Plural
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/i18n/i18n.go:

129
func Plural(pluralCount any) utils.OptionFunc[localizeOption] {
130
        return func(o *localizeOption) {
131
                o.pluralCount = pluralCount
132
        }
133
}
Package Overview: github.com/wfusion/gofusion/internal/configor 59.3%

Please select a function to see what's left for testing.

Configor.GetErrorOnUnmatchedKeys(...) github.com/wfusion/gofusion/internal/configor/configor.go 100.0% 1/1
Configor.Load(...) github.com/wfusion/gofusion/internal/configor/configor.go 85.7% 6/7
@166:6(...) github.com/wfusion/gofusion/internal/configor/configor.go 84.6% 11/13
Configor.load(...) github.com/wfusion/gofusion/internal/configor/utils.go 82.4% 28/34
@96:13(...) github.com/wfusion/gofusion/internal/configor/configor.go 77.8% 7/9
@316:11(...) github.com/wfusion/gofusion/internal/configor/utils.go 75.0% 9/12
unmarshalJSON(...) github.com/wfusion/gofusion/internal/configor/utils.go 75.0% 6/8
unmarshalToml(...) github.com/wfusion/gofusion/internal/configor/utils.go 75.0% 3/4
Configor.GetEnvironment(...) github.com/wfusion/gofusion/internal/configor/configor.go 71.4% 5/7
getPrefixForStruct(...) github.com/wfusion/gofusion/internal/configor/utils.go 66.7% 2/3
Configor.getConfigurationFileWithENVPrefix(...) github.com/wfusion/gofusion/internal/configor/utils.go 62.5% 5/8
Configor.getConfigurationFiles(...) github.com/wfusion/gofusion/internal/configor/utils.go 61.3% 19/31
New(...) github.com/wfusion/gofusion/internal/configor/configor.go 60.0% 9/15
Configor.getENVPrefix(...) github.com/wfusion/gofusion/internal/configor/utils.go 60.0% 3/5
Configor.processTags(...) github.com/wfusion/gofusion/internal/configor/utils.go 57.5% 23/40
Configor.processFile(...) github.com/wfusion/gofusion/internal/configor/utils.go 27.3% 9/33
@345:8(...) github.com/wfusion/gofusion/internal/configor/utils.go 25.0% 1/4
@114:18(...) github.com/wfusion/gofusion/internal/configor/configor.go 0.0% 0/9
@145:14(...) github.com/wfusion/gofusion/internal/configor/utils.go 0.0% 0/1
Load(...) github.com/wfusion/gofusion/internal/configor/configor.go 0.0% 0/1
ENV(...) github.com/wfusion/gofusion/internal/configor/configor.go 0.0% 0/1
@111:18(...) github.com/wfusion/gofusion/internal/configor/configor.go 0.0% 0/1
UnmatchedTomlKeysError.Error(...) github.com/wfusion/gofusion/internal/configor/utils.go 0.0% 0/1
func Configor.GetErrorOnUnmatchedKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

153
func (c *Configor) GetErrorOnUnmatchedKeys() bool {
154
        return c.ErrorOnUnmatchedKeys
155
}
func Configor.Load
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

158
func (c *Configor) Load(config any, files ...string) (err error) {
159
        defaultValue := reflect.Indirect(reflect.ValueOf(config))
160
        if !defaultValue.CanAddr() {
161
                return fmt.Errorf("config %v should be addressable", config)
162
        }
163
        err, _ = c.load(config, false, files...)
164
165
        if c.Config.AutoReload {
166
                go func() {
167
                        timer := time.NewTimer(c.Config.AutoReloadInterval)
168
                        for range timer.C {
169
                                reflectPtr := reflect.New(reflect.ValueOf(config).Elem().Type())
170
                                reflectPtr.Elem().Set(defaultValue)
171
172
                                var changed bool
173
                                if err, changed = c.load(reflectPtr.Interface(), true, files...); err == nil && changed {
174
                                        reflect.ValueOf(config).Elem().Set(reflectPtr.Elem())
175
                                        if c.Config.AutoReloadCallback != nil {
176
                                                c.Config.AutoReloadCallback(config)
177
                                        }
178
                                } else if err != nil {
179
                                        if !c.Silent {
180
                                                fmt.Printf("Failed to reload configuration from %v, got error %v\n", files, err)
181
                                        }
182
                                }
183
                                timer.Reset(c.Config.AutoReloadInterval)
184
                        }
185
                }()
186
        }
187
        return
188
}
func @166:6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

166
func() {
167
                        timer := time.NewTimer(c.Config.AutoReloadInterval)
168
                        for range timer.C {
169
                                reflectPtr := reflect.New(reflect.ValueOf(config).Elem().Type())
170
                                reflectPtr.Elem().Set(defaultValue)
171
172
                                var changed bool
173
                                if err, changed = c.load(reflectPtr.Interface(), true, files...); err == nil && changed {
174
                                        reflect.ValueOf(config).Elem().Set(reflectPtr.Elem())
175
                                        if c.Config.AutoReloadCallback != nil {
176
                                                c.Config.AutoReloadCallback(config)
177
                                        }
178
                                } else if err != nil {
179
                                        if !c.Silent {
180
                                                fmt.Printf("Failed to reload configuration from %v, got error %v\n", files, err)
181
                                        }
182
                                }
183
                                timer.Reset(c.Config.AutoReloadInterval)
184
                        }
185
                }
func Configor.load
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

344
func (c *Configor) load(config any, watchMode bool, files ...string) (err error, changed bool) {
345
        defer func() {
346
                if c.Config.Debug || c.Config.Verbose {
347
                        if err != nil {
348
                                fmt.Printf("Failed to load configuration from %v, got %v\n", files, err)
349
                        }
350
351
                        fmt.Printf("Configuration:\n  %#v\n", config)
352
                }
353
        }()
354
355
        configFiles, configModTimeMap, hashMap := c.getConfigurationFiles(c.Config, watchMode, files...)
356
        if watchMode && len(configModTimeMap) == len(c.configModTimes) && len(hashMap) == len(c.configHash) {
357
                var changed bool
358
                for f, curModTime := range configModTimeMap {
359
                        curHash := hashMap[f]
360
                        preHash, ok1 := c.configHash[f]
361
                        preModTime, ok2 := c.configModTimes[f]
362
                        if changed = !ok1 || !ok2 || curModTime.After(preModTime) || curHash != preHash; changed {
363
                                break
364
                        }
365
                }
366
367
                if !changed {
368
                        return nil, false
369
                }
370
        }
371
372
        type withCallback interface {
373
                BeforeLoad(any)
374
                AfterLoad(any)
375
        }
376
        if cb, ok := config.(withCallback); ok {
377
                cb.BeforeLoad(config)
378
                defer cb.AfterLoad(config)
379
        }
380
381
        for _, file := range configFiles {
382
                if c.Config.Debug || c.Config.Verbose {
383
                        fmt.Printf("Loading configurations from file '%v'...\n", file)
384
                }
385
                if err = c.processFile(config, file, c.GetErrorOnUnmatchedKeys()); err != nil {
386
                        return err, true
387
                }
388
        }
389
390
        // process defaults after process file because map struct should be assigned first
391
        _ = utils.ParseTag(config, utils.ParseTagName("default"), utils.ParseTagUnmarshalType(utils.UnmarshalTypeYaml))
392
393
        // process file again to ensure read config from file
394
        for _, file := range configFiles {
395
                if c.Config.Debug || c.Config.Verbose {
396
                        fmt.Printf("Loading configurations from file '%v'...\n", file)
397
                }
398
                if err = c.processFile(config, file, c.GetErrorOnUnmatchedKeys()); err != nil {
399
                        return err, true
400
                }
401
        }
402
403
        c.configHash = hashMap
404
        c.configModTimes = configModTimeMap
405
406
        if prefix := c.getENVPrefix(config); prefix == "-" {
407
                err = c.processTags(config)
408
        } else {
409
                err = c.processTags(config, prefix)
410
        }
411
412
        // process defaults
413
        _ = utils.ParseTag(config, utils.ParseTagName("default"), utils.ParseTagUnmarshalType(utils.UnmarshalTypeYaml))
414
415
        return err, true
416
}
func @96:13
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

96
func(name string) (h string, err error) {
97
                        var file fs.File
98
                        if file, err = os.Open(name); err != nil {
99
                                return
100
                        }
101
                        defer utils.CloseAnyway(file)
102
                        sha256Hash := sha256.New()
103
                        if _, err = io.Copy(sha256Hash, file); err != nil {
104
                                return
105
                        }
106
                        h = string(sha256Hash.Sum(nil))
107
                        return
108
                }
func @316:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

316
func(field reflect.Value, fieldStruct reflect.StructField) {
317
                                        if !configValue.IsZero() {
318
                                                // load slice from env
319
                                                newVal := reflect.New(field.Type().Elem()).Elem()
320
                                                if newVal.Kind() == reflect.Struct {
321
                                                        idx := 0
322
                                                        for {
323
                                                                newVal = reflect.New(field.Type().Elem()).Elem()
324
                                                                if err := c.processTags(newVal.Addr().Interface(), append(
325
                                                                        getPrefixForStruct(prefixes, &fieldStruct), fmt.Sprint(idx))...); err != nil {
326
                                                                        return // err
327
                                                                } else if reflect.DeepEqual(newVal.Interface(),
328
                                                                        reflect.New(field.Type().Elem()).Elem().Interface()) {
329
                                                                        break
330
                                                                } else {
331
                                                                        idx++
332
                                                                        field.Set(reflect.Append(field, newVal))
333
                                                                }
334
                                                        }
335
                                                }
336
                                        }
337
                                }
func unmarshalJSON
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

209
func unmarshalJSON(data []byte, config any, errorOnUnmatchedKeys bool) error {
210
        reader := strings.NewReader(string(data))
211
        decoder := json.NewDecoder(reader)
212
213
        if errorOnUnmatchedKeys {
214
                decoder.DisallowUnknownFields()
215
        }
216
217
        err := decoder.Decode(config)
218
        if err != nil && err != io.EOF {
219
                return err
220
        }
221
        return nil
222
}
func unmarshalToml
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

198
func unmarshalToml(data []byte, config any, errorOnUnmatchedKeys bool) error {
199
        metadata, err := toml.Decode(string(data), config)
200
        if err == nil && len(metadata.Undecoded()) > 0 && errorOnUnmatchedKeys {
201
                return &UnmatchedTomlKeysError{Keys: metadata.Undecoded()}
202
        }
203
        return err
204
}
func Configor.GetEnvironment
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

135
func (c *Configor) GetEnvironment() string {
136
        if c.Environment == "" {
137
                if env := os.Getenv("CONFIGOR_ENV"); env != "" {
138
                        return env
139
                }
140
141
                if testRegexp.MatchString(os.Args[0]) {
142
                        return "test"
143
                }
144
145
                return "development"
146
        }
147
        return c.Environment
148
}
func getPrefixForStruct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

224
func getPrefixForStruct(prefixes []string, fieldStruct *reflect.StructField) []string {
225
        if fieldStruct.Anonymous && fieldStruct.Tag.Get("anonymous") == "true" {
226
                return prefixes
227
        }
228
        return append(prefixes, fieldStruct.Name)
229
}
func Configor.getConfigurationFileWithENVPrefix
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

71
func (c *Configor) getConfigurationFileWithENVPrefix(file, env string) (string, time.Time, string, error) {
72
        var (
73
                envFile string
74
                extname = path.Ext(file)
75
        )
76
77
        if extname == "" {
78
                envFile = fmt.Sprintf("%v.%v", file, env)
79
        } else {
80
                envFile = fmt.Sprintf("%v.%v%v", strings.TrimSuffix(file, extname), env, extname)
81
        }
82
83
        if fileInfo, err := c.statFunc(envFile); err == nil && fileInfo.Mode().IsRegular() {
84
                fileHash, _ := c.hashFunc(envFile)
85
                return envFile, fileInfo.ModTime(), fileHash, nil
86
        }
87
        return "", time.Now(), "", fmt.Errorf("failed to find file %v", file)
88
}
func Configor.getConfigurationFiles
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

90
func (c *Configor) getConfigurationFiles(config *Config, watchMode bool, files ...string) (
91
        []string, map[string]time.Time, map[string]string) {
92
        resultKeys := make([]string, 0, len(files))
93
        hashResult := make(map[string]string, len(files))
94
        modTimeResult := make(map[string]time.Time, len(files))
95
        if !watchMode && (c.Config.Debug || c.Config.Verbose) {
96
                fmt.Printf("Current environment: '%v'\n", c.GetEnvironment())
97
        }
98
99
        for i := len(files) - 1; i >= 0; i-- {
100
                foundFile := false
101
                file := files[i]
102
103
                // check configuration
104
                if fileInfo, err := c.statFunc(file); err == nil && fileInfo.Mode().IsRegular() {
105
                        foundFile = true
106
                        resultKeys = append(resultKeys, file)
107
                        modTimeResult[file] = fileInfo.ModTime()
108
                        if hash, err := c.hashFunc(file); err == nil {
109
                                hashResult[file] = hash
110
                        }
111
                }
112
113
                // check configuration with env
114
                if file, modTime, hash, err := c.getConfigurationFileWithENVPrefix(file, c.GetEnvironment()); err == nil {
115
                        foundFile = true
116
                        resultKeys = append(resultKeys, file)
117
                        modTimeResult[file] = modTime
118
                        if hash != "" {
119
                                hashResult[file] = hash
120
                        }
121
                }
122
123
                // check example configuration
124
                if !foundFile {
125
                        if example, modTime, hash, err := c.getConfigurationFileWithENVPrefix(file, "example"); err == nil {
126
                                if !watchMode && !c.Silent {
127
                                        log.Printf("Failed to find configuration %v, using example file %v\n", file, example)
128
                                }
129
                                resultKeys = append(resultKeys, example)
130
                                modTimeResult[example] = modTime
131
                                if hash != "" {
132
                                        hashResult[file] = hash
133
                                }
134
                        } else if !c.Silent {
135
                                fmt.Printf("Failed to find configuration %v\n", file)
136
                        }
137
                }
138
        }
139
        return resultKeys, modTimeResult, hashResult
140
}
func New
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

70
func New(config *Config) *Configor {
71
        if config == nil {
72
                config = &Config{}
73
        }
74
75
        if os.Getenv("CONFIGOR_DEBUG_MODE") != "" {
76
                config.Debug = true
77
        }
78
79
        if os.Getenv("CONFIGOR_VERBOSE_MODE") != "" {
80
                config.Verbose = true
81
        }
82
83
        if os.Getenv("CONFIGOR_SILENT_MODE") != "" {
84
                config.Silent = true
85
        }
86
87
        if config.AutoReload && config.AutoReloadInterval == 0 {
88
                config.AutoReloadInterval = time.Second
89
        }
90
91
        cfg := &Configor{
92
                Config:         config,
93
                configHash:     make(map[string]string),
94
                configModTimes: make(map[string]time.Time),
95
                statFunc:       os.Stat,
96
                hashFunc: func(name string) (h string, err error) {
97
                        var file fs.File
98
                        if file, err = os.Open(name); err != nil {
99
                                return
100
                        }
101
                        defer utils.CloseAnyway(file)
102
                        sha256Hash := sha256.New()
103
                        if _, err = io.Copy(sha256Hash, file); err != nil {
104
                                return
105
                        }
106
                        h = string(sha256Hash.Sum(nil))
107
                        return
108
                },
109
        }
110
        if cfg.FS != nil {
111
                cfg.statFunc = func(name string) (os.FileInfo, error) {
112
                        return fs.Stat(cfg.FS, name)
113
                }
114
                cfg.hashFunc = func(name string) (h string, err error) {
115
                        var file fs.File
116
                        if file, err = cfg.FS.Open(name); err != nil {
117
                                return
118
                        }
119
                        defer utils.CloseAnyway(file)
120
                        sha256Hash := sha256.New()
121
                        if _, err = io.Copy(sha256Hash, file); err != nil {
122
                                return
123
                        }
124
                        h = string(sha256Hash.Sum(nil))
125
                        return
126
                }
127
        }
128
129
        return cfg
130
}
func Configor.getENVPrefix
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

61
func (c *Configor) getENVPrefix(config any) string {
62
        if c.Config.ENVPrefix == "" {
63
                if prefix := os.Getenv("CONFIGOR_ENV_PREFIX"); prefix != "" {
64
                        return prefix
65
                }
66
                return "Configor"
67
        }
68
        return c.Config.ENVPrefix
69
}
func Configor.processTags
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

231
func (c *Configor) processTags(config any, prefixes ...string) error {
232
        configValue := reflect.Indirect(reflect.ValueOf(config))
233
        if configValue.Kind() != reflect.Struct {
234
                return errors.New("invalid config, should be struct")
235
        }
236
237
        configType := configValue.Type()
238
        for i := 0; i < configType.NumField(); i++ {
239
                var (
240
                        envNames    []string
241
                        fieldStruct = configType.Field(i)
242
                        field       = configValue.Field(i)
243
                        envName     = fieldStruct.Tag.Get("env") // read configuration from shell env
244
                )
245
246
                if !field.CanAddr() || !field.CanInterface() {
247
                        continue
248
                }
249
250
                if envName == "" {
251
                        envNames = append(envNames,
252
                                strings.Join(append(prefixes, fieldStruct.Name), "_")) // Configor_DB_Name
253
                        envNames = append(envNames,
254
                                strings.ToUpper(strings.Join(append(prefixes, fieldStruct.Name), "_"))) // CONFIGOR_DB_NAME
255
                } else {
256
                        envNames = []string{envName}
257
                }
258
259
                if c.Config.Verbose {
260
                        fmt.Printf("Trying to load struct `%v`'s field `%v` from env %v\n",
261
                                configType.Name(), fieldStruct.Name, strings.Join(envNames, ", "))
262
                }
263
264
                // Load From Shell ENV
265
                for _, env := range envNames {
266
                        if value := os.Getenv(env); value != "" {
267
                                if c.Config.Debug || c.Config.Verbose {
268
                                        fmt.Printf("Loading configuration for struct `%v`'s field `%v` from env %v...\n",
269
                                                configType.Name(), fieldStruct.Name, env)
270
                                }
271
272
                                switch reflect.Indirect(field).Kind() {
273
                                case reflect.Bool:
274
                                        switch strings.ToLower(value) {
275
                                        case "", "0", "f", "false":
276
                                                field.Set(reflect.ValueOf(false))
277
                                        default:
278
                                                field.Set(reflect.ValueOf(true))
279
                                        }
280
                                case reflect.String:
281
                                        field.Set(reflect.ValueOf(value))
282
                                default:
283
                                        if err := yaml.Unmarshal([]byte(value), field.Addr().Interface()); err != nil {
284
                                                return err
285
                                        }
286
                                }
287
                                break
288
                        }
289
                }
290
291
                if isBlank := reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()); isBlank &&
292
                        fieldStruct.Tag.Get("required") == "true" {
293
                        // return error if it is required but blank
294
                        return errors.New(fieldStruct.Name + " is required, but blank")
295
                }
296
297
                field = utils.IndirectValue(field)
298
                if field.Kind() == reflect.Struct {
299
                        if err := c.processTags(field.Addr().Interface(),
300
                                getPrefixForStruct(prefixes, &fieldStruct)...); err != nil {
301
                                return err
302
                        }
303
                }
304
305
                if field.Kind() == reflect.Slice {
306
                        if arrLen := field.Len(); arrLen > 0 {
307
                                for i := 0; i < arrLen; i++ {
308
                                        if reflect.Indirect(field.Index(i)).Kind() == reflect.Struct {
309
                                                if err := c.processTags(field.Index(i).Addr().Interface(),
310
                                                        append(getPrefixForStruct(prefixes, &fieldStruct), fmt.Sprint(i))...); err != nil {
311
                                                        return err
312
                                                }
313
                                        }
314
                                }
315
                        } else {
316
                                defer func(field reflect.Value, fieldStruct reflect.StructField) {
317
                                        if !configValue.IsZero() {
318
                                                // load slice from env
319
                                                newVal := reflect.New(field.Type().Elem()).Elem()
320
                                                if newVal.Kind() == reflect.Struct {
321
                                                        idx := 0
322
                                                        for {
323
                                                                newVal = reflect.New(field.Type().Elem()).Elem()
324
                                                                if err := c.processTags(newVal.Addr().Interface(), append(
325
                                                                        getPrefixForStruct(prefixes, &fieldStruct), fmt.Sprint(idx))...); err != nil {
326
                                                                        return // err
327
                                                                } else if reflect.DeepEqual(newVal.Interface(),
328
                                                                        reflect.New(field.Type().Elem()).Elem().Interface()) {
329
                                                                        break
330
                                                                } else {
331
                                                                        idx++
332
                                                                        field.Set(reflect.Append(field, newVal))
333
                                                                }
334
                                                        }
335
                                                }
336
                                        }
337
                                }(field, fieldStruct)
338
                        }
339
                }
340
        }
341
        return nil
342
}
func Configor.processFile
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

142
func (c *Configor) processFile(config any, file string, errorOnUnmatchedKeys bool) error {
143
        readFile := ioutil.ReadFile
144
        if c.FS != nil {
145
                readFile = func(filename string) ([]byte, error) {
146
                        return fs.ReadFile(c.FS, filename)
147
                }
148
        }
149
        data, err := readFile(file)
150
        if err != nil {
151
                return err
152
        }
153
154
        switch {
155
        case strings.HasSuffix(file, ".yaml") || strings.HasSuffix(file, ".yml"):
156
                if errorOnUnmatchedKeys {
157
                        decoder := yaml.NewDecoder(bytes.NewBuffer(data))
158
                        decoder.KnownFields(true)
159
                        return decoder.Decode(config)
160
                }
161
                return yaml.Unmarshal(data, config)
162
        case strings.HasSuffix(file, ".toml"):
163
                return unmarshalToml(data, config, errorOnUnmatchedKeys)
164
        case strings.HasSuffix(file, ".json"):
165
                return unmarshalJSON(data, config, errorOnUnmatchedKeys)
166
        default:
167
                if err := unmarshalToml(data, config, errorOnUnmatchedKeys); err == nil {
168
                        return nil
169
                } else if errUnmatchedKeys, ok := err.(*UnmatchedTomlKeysError); ok {
170
                        return errUnmatchedKeys
171
                }
172
173
                if err := unmarshalJSON(data, config, errorOnUnmatchedKeys); err == nil {
174
                        return nil
175
                } else if strings.Contains(err.Error(), "json: unknown field") {
176
                        return err
177
                }
178
179
                var yamlError error
180
                if errorOnUnmatchedKeys {
181
                        decoder := yaml.NewDecoder(bytes.NewBuffer(data))
182
                        decoder.KnownFields(true)
183
                        yamlError = decoder.Decode(config)
184
                } else {
185
                        yamlError = yaml.Unmarshal(data, config)
186
                }
187
188
                if yamlError == nil {
189
                        return nil
190
                } else if yErr, ok := yamlError.(*yaml.TypeError); ok {
191
                        return yErr
192
                }
193
194
                return errors.New("failed to decode config")
195
        }
196
}
func @345:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

345
func() {
346
                if c.Config.Debug || c.Config.Verbose {
347
                        if err != nil {
348
                                fmt.Printf("Failed to load configuration from %v, got %v\n", files, err)
349
                        }
350
351
                        fmt.Printf("Configuration:\n  %#v\n", config)
352
                }
353
        }
func @114:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

114
func(name string) (h string, err error) {
115
                        var file fs.File
116
                        if file, err = cfg.FS.Open(name); err != nil {
117
                                return
118
                        }
119
                        defer utils.CloseAnyway(file)
120
                        sha256Hash := sha256.New()
121
                        if _, err = io.Copy(sha256Hash, file); err != nil {
122
                                return
123
                        }
124
                        h = string(sha256Hash.Sum(nil))
125
                        return
126
                }
func @145:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

145
func(filename string) ([]byte, error) {
146
                        return fs.ReadFile(c.FS, filename)
147
                }
func Load
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

196
func Load(config any, files ...string) error {
197
        return New(nil).Load(config, files...)
198
}
func ENV
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

191
func ENV() string {
192
        return New(nil).GetEnvironment()
193
}
func @111:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/configor.go:

111
func(name string) (os.FileInfo, error) {
112
                        return fs.Stat(cfg.FS, name)
113
                }
func UnmatchedTomlKeysError.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/configor/utils.go:

57
func (e *UnmatchedTomlKeysError) Error() string {
58
        return fmt.Sprintf("There are keys in the config file that do not match any field in the given struct: %v", e.Keys)
59
}
Package Overview: github.com/wfusion/gofusion/internal/util/payload 60.2%

Please select a function to see what's left for testing.

@41:9(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
Context(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
@29:9(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
Serialize(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
@35:9(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
Compress(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
Type(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
@47:9(...) github.com/wfusion/gofusion/internal/util/payload/types.go 100.0% 1/1
unsealV1(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 85.4% 35/41
unsealV1T(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 75.6% 31/41
Seal(...) github.com/wfusion/gofusion/internal/util/payload/seal.go 69.8% 37/53
Unseal(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 66.7% 6/9
UnsealT(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 66.7% 6/9
UnsealRaw(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 40.0% 4/10
unsealRawV1(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 0.0% 0/22
defaultUnseal(...) github.com/wfusion/gofusion/internal/util/payload/unseal.go 0.0% 0/16
@53:9(...) github.com/wfusion/gofusion/internal/util/payload/types.go 0.0% 0/1
Version(...) github.com/wfusion/gofusion/internal/util/payload/types.go 0.0% 0/1
func @41:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

41
func(o *option) {
42
                o.compressType = compressType
43
        }
func Context
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

28
func Context(ctx context.Context) utils.OptionFunc[option] {
29
        return func(o *option) {
30
                o.ctx = ctx
31
        }
32
}
func @29:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

29
func(o *option) {
30
                o.ctx = ctx
31
        }
func Serialize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

34
func Serialize(serializeType serialize.Algorithm) utils.OptionFunc[option] {
35
        return func(o *option) {
36
                o.serializeType = serializeType
37
        }
38
}
func @35:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

35
func(o *option) {
36
                o.serializeType = serializeType
37
        }
func Compress
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

40
func Compress(compressType compress.Algorithm) utils.OptionFunc[option] {
41
        return func(o *option) {
42
                o.compressType = compressType
43
        }
44
}
func Type
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

46
func Type(typ reflect.Type) utils.OptionFunc[option] {
47
        return func(o *option) {
48
                o.dataType = typ
49
        }
50
}
func @47:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

47
func(o *option) {
48
                o.dataType = typ
49
        }
func unsealV1
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

41
func unsealV1(inf, src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
42
        opt := utils.ApplyOptions[option](opts...)
43
        serializeType := serialize.ParseAlgorithm(serialize.Algorithm(inf[1]))
44
        if opt.serializeType.IsValid() {
45
                serializeType = opt.serializeType
46
        }
47
        compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
48
        if opt.compressType.IsValid() {
49
                compressType = opt.compressType
50
        }
51
52
        isRaw := false
53
        if inf[3] == 1 {
54
                isRaw = true
55
        }
56
57
        // unseal encrypted inf
58
        encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
59
        _, src = src[:encryptedInfLength], src[encryptedInfLength:]
60
61
        // unseal context
62
        contextLengthBytes, src := src[:8], src[8:]
63
        contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
64
        if contextLength > 0 {
65
                var contextBytes []byte
66
                contextBytes, src = src[:contextLength], src[contextLength:]
67
                ctx = fusCtx.New(fusCtx.Context(contextBytes))
68
        }
69
70
        // unseal data type
71
        inf, src = src[:8], src[8:]
72
        structNameLength := binary.LittleEndian.Uint64(inf)
73
        structName, src := src[:structNameLength], src[structNameLength:]
74
        if !isRaw && opt.dataType == nil {
75
                if opt.dataType = inspect.TypeOf(string(structName)); opt.dataType == nil {
76
                        opt.dataType = reflect.TypeOf((*any)(nil)).Elem()
77
                }
78
        }
79
80
        // unseal data
81
        // unseal data length
82
        _, src = src[:8], src[8:]
83
        // binary.LittleEndian.Uint64(src[:8])
84
85
        // unseal data
86
        var decoded []byte
87
        if compressType.IsValid() {
88
                decoded, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
89
        } else {
90
                decoded = src
91
        }
92
        if err != nil {
93
                return
94
        }
95
96
        if !serializeType.IsValid() {
97
                dst = decoded
98
        } else {
99
                dstBuffer, cb := utils.BytesBufferPool.Get(nil)
100
                defer cb()
101
                dstBuffer.Write(decoded)
102
103
                unmarshalFunc := serialize.UnmarshalStreamFuncByType(serializeType, opt.dataType)
104
                if dst, err = unmarshalFunc(dstBuffer); err != nil {
105
                        return
106
                }
107
        }
108
109
        ok = true
110
        return
111
}
func unsealV1T
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

134
func unsealV1T[T any](inf, src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst T, ok bool, err error) {
135
        opt := utils.ApplyOptions[option](opts...)
136
        serializeType := serialize.ParseAlgorithm(serialize.Algorithm(inf[1]))
137
        if opt.serializeType.IsValid() {
138
                serializeType = opt.serializeType
139
        }
140
        compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
141
        if opt.compressType.IsValid() {
142
                compressType = opt.compressType
143
        }
144
145
        isRaw := false
146
        if inf[3] == 1 {
147
                isRaw = true
148
        }
149
150
        // unseal encrypted inf
151
        encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
152
        _, src = src[:encryptedInfLength], src[encryptedInfLength:]
153
154
        // unseal context
155
        contextLengthBytes, src := src[:8], src[8:]
156
        contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
157
        if contextLength > 0 {
158
                var contextBytes []byte
159
                contextBytes, src = src[:contextLength], src[contextLength:]
160
                ctx = fusCtx.New(fusCtx.Context(contextBytes))
161
        }
162
163
        // unseal data type
164
        inf, src = src[:8], src[8:]
165
        structNameLength := binary.LittleEndian.Uint64(inf)
166
        structName, src := src[:structNameLength], src[structNameLength:]
167
        if !isRaw && opt.dataType == nil {
168
                if opt.dataType = inspect.TypeOf(string(structName)); opt.dataType == nil {
169
                        opt.dataType = reflect.TypeOf((*any)(nil)).Elem()
170
                }
171
        }
172
173
        // unseal data
174
        // unseal data length
175
        _, src = src[:8], src[8:]
176
        // binary.LittleEndian.Uint64(src[:8])
177
178
        // unseal data
179
        var decoded []byte
180
        if compressType.IsValid() {
181
                decoded, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
182
        } else {
183
                decoded = src
184
        }
185
        if err != nil {
186
                return
187
        }
188
189
        if !serializeType.IsValid() {
190
                dst = reflect.ValueOf(decoded).Convert(reflect.TypeOf(new(T)).Elem()).Interface().(T)
191
        } else {
192
                dstBuffer, cb := utils.BytesBufferPool.Get(nil)
193
                defer cb()
194
                dstBuffer.Write(decoded)
195
196
                unmarshalFunc := serialize.UnmarshalStreamFunc[T](serializeType)
197
                if dst, err = unmarshalFunc(dstBuffer); err != nil {
198
                        return
199
                }
200
        }
201
202
        ok = true
203
        return
204
}
func Seal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/seal.go:

14
func Seal(data any, opts ...utils.OptionExtender) (dst []byte, err error) {
15
        opt := utils.ApplyOptions[option](opts...)
16
17
        dstBuffer, cb := utils.BytesBufferPool.Get(nil)
18
        defer cb()
19
20
        dbytes, ok1 := data.([]byte)
21
        dstring, ok2 := data.(string)
22
        isRaw := ok1 || ok2
23
24
        // magic number
25
        if err = binary.Write(dstBuffer, binary.LittleEndian, sealMagicNumber); err != nil {
26
                return
27
        }
28
29
        // seal info
30
        inf := sealTypeNumber
31
        if opt.version > 0 {
32
                inf[0] = opt.version
33
        }
34
        if isRaw {
35
                inf[3] = 1
36
        } else {
37
                inf[1] = opt.serializeType.Value()
38
        }
39
        inf[2] = opt.compressType.Value()
40
        if err = binary.Write(dstBuffer, binary.LittleEndian, inf[:]); err != nil {
41
                return
42
        }
43
44
        // seal encrypted info TODO
45
46
        // seal context
47
        if opt.ctx == nil {
48
                if err = binary.Write(dstBuffer, binary.LittleEndian, uint64(0)); err != nil {
49
                        return
50
                }
51
        } else {
52
                ctxBytes := fusCtx.Flatten(opt.ctx).Marshal()
53
                if err = binary.Write(dstBuffer, binary.LittleEndian, uint64(len(ctxBytes))); err != nil {
54
                        return
55
                }
56
                if err = binary.Write(dstBuffer, binary.LittleEndian, ctxBytes); err != nil {
57
                        return
58
                }
59
        }
60
61
        // seal data type
62
        dt := utils.IndirectValue(reflect.ValueOf(data)).Type()
63
        structName := dt.PkgPath() + "." + dt.Name()
64
        if err = binary.Write(dstBuffer, binary.LittleEndian, uint64(len(structName))); err != nil {
65
                return
66
        }
67
        if err = binary.Write(dstBuffer, binary.LittleEndian, []byte(structName)); err != nil {
68
                return
69
        }
70
71
        // seal data
72
        marshaledBuffer, cb := utils.BytesBufferPool.Get(nil)
73
        defer cb()
74
75
        if isRaw {
76
                switch {
77
                case ok1:
78
                        marshaledBuffer.Write(dbytes)
79
                case ok2:
80
                        marshaledBuffer.WriteString(dstring)
81
                }
82
        } else {
83
                marshalFunc := serialize.MarshalStreamFunc(opt.serializeType, serialize.JsonEscapeHTML(false))
84
                if err = marshalFunc(marshaledBuffer, data); err != nil {
85
                        return
86
                }
87
        }
88
89
        var encoded []byte
90
        if opt.compressType.IsValid() {
91
                encoded, err = encode.From(marshaledBuffer.Bytes()).Encode(encode.Compress(opt.compressType)).ToBytes()
92
        } else {
93
                encoded = marshaledBuffer.Bytes()
94
        }
95
        if err != nil {
96
                return
97
        }
98
99
        if err = binary.Write(dstBuffer, binary.LittleEndian, uint64(len(encoded))); err != nil {
100
                return
101
        }
102
        if err = binary.Write(dstBuffer, binary.LittleEndian, encoded); err != nil {
103
                return
104
        }
105
106
        dst = make([]byte, dstBuffer.Len())
107
        copy(dst, dstBuffer.Bytes())
108
        return
109
}
func Unseal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

20
func Unseal(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
21
        if len(src) <= sealPrefixLength {
22
                return defaultUnseal(src, opts...)
23
        }
24
25
        // unseal magic number
26
        magicNumber, next := src[:4], src[4:]
27
        if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
28
                return defaultUnseal(src, opts...)
29
        }
30
31
        // unseal info
32
        inf, next := next[:len(sealTypeNumber)], next[len(sealTypeNumber):]
33
        switch inf[0] {
34
        case 1:
35
                return unsealV1(inf, next, opts...)
36
        default:
37
                panic(errors.Errorf("unsupported message version for unseal: %v", inf[0]))
38
        }
39
}
func UnsealT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

113
func UnsealT[T any](src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst T, ok bool, err error) {
114
        if len(src) <= sealPrefixLength {
115
                return
116
        }
117
118
        // unseal magic number
119
        magicNumber, src := src[:4], src[4:]
120
        if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
121
                return
122
        }
123
124
        // unseal info
125
        inf, src := src[:len(sealTypeNumber)], src[len(sealTypeNumber):]
126
        switch inf[0] {
127
        case 1:
128
                return unsealV1T[T](inf, src, opts...)
129
        default:
130
                panic(errors.Errorf("unsupported message version for unseal: %v", inf[0]))
131
        }
132
}
func UnsealRaw
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

206
func UnsealRaw(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst []byte, isRaw bool, err error) {
207
        if len(src) <= sealPrefixLength {
208
                return nil, src, true, nil
209
        }
210
211
        // unseal magic number
212
        magicNumber, next := src[:4], src[4:]
213
        if binary.LittleEndian.Uint32(magicNumber) != sealMagicNumber {
214
                return nil, src, true, nil
215
        }
216
217
        // unseal info
218
        inf, src := next[:len(sealTypeNumber)], next[len(sealTypeNumber):]
219
        switch inf[0] {
220
        case 1:
221
                return unsealRawV1(inf, src, opts...)
222
        default:
223
                panic(errors.Errorf("unsupported message version for unseal raw: %v", inf[0]))
224
        }
225
        return
226
}
func unsealRawV1
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

228
func unsealRawV1(inf, src []byte, opts ...utils.OptionExtender) (
229
        ctx context.Context, dst []byte, isRaw bool, err error) {
230
        opt := utils.ApplyOptions[option](opts...)
231
        compressType := compress.ParseAlgorithm(compress.Algorithm(inf[2]))
232
        if opt.compressType.IsValid() {
233
                compressType = opt.compressType
234
        }
235
        if src[3] == 1 {
236
                isRaw = true
237
        }
238
239
        // unseal encrypted inf
240
        encryptedInfLength := binary.LittleEndian.Uint32(inf[4:])
241
        _, src = src[:encryptedInfLength], src[encryptedInfLength:]
242
243
        // unseal context
244
        contextLengthBytes, src := src[:8], src[8:]
245
        contextLength := binary.LittleEndian.Uint64(contextLengthBytes)
246
        if contextLength > 0 {
247
                var contextBytes []byte
248
                contextBytes, src = src[:contextLength], src[contextLength:]
249
                ctx = fusCtx.New(fusCtx.Context(contextBytes))
250
        }
251
252
        // unseal data type
253
        inf, src = src[:8], src[8:]
254
        structNameLength := binary.LittleEndian.Uint64(inf)
255
        _, src = src[:structNameLength], src[structNameLength:]
256
257
        // unseal data
258
        // unseal data length
259
        _, src = src[:8], src[8:]
260
        // binary.LittleEndian.Uint64(src[:8])
261
262
        // unseal data
263
        if compressType.IsValid() {
264
                dst, err = encode.From(src).Decode(encode.Compress(compressType)).ToBytes()
265
        } else {
266
                dst = src
267
        }
268
        return
269
}
func defaultUnseal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/unseal.go:

271
func defaultUnseal(src []byte, opts ...utils.OptionExtender) (ctx context.Context, dst any, ok bool, err error) {
272
        opt := utils.ApplyOptions[option](opts...)
273
        if opt.compressType.IsValid() {
274
                if src, err = encode.From(src).Decode(encode.Compress(opt.compressType)).ToBytes(); err != nil {
275
                        return
276
                }
277
        }
278
        if !opt.serializeType.IsValid() {
279
                // try to convert directly
280
                srcVal := reflect.ValueOf(src)
281
                if srcVal.CanConvert(opt.dataType) {
282
                        return nil, srcVal.Convert(opt.dataType).Interface(), false, nil
283
                }
284
285
                // try to map the structure
286
                out := reflect.New(opt.dataType).Interface()
287
                if err = mapstructure.Decode(src, out); err != nil {
288
                        return
289
                }
290
                dst = reflect.ValueOf(out).Elem()
291
                return
292
        }
293
        unmarshalFunc := serialize.UnmarshalFuncByType(opt.serializeType, opt.dataType, serialize.JsonEscapeHTML(false))
294
        dst, err = unmarshalFunc(src)
295
        return
296
}
func @53:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

53
func(o *option) {
54
                o.version = ver
55
        }
func Version
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/internal/util/payload/types.go:

52
func Version(ver uint8) utils.OptionFunc[option] {
53
        return func(o *option) {
54
                o.version = ver
55
        }
56
}
Package Overview: github.com/wfusion/gofusion/lock 80.9%

Please select a function to see what's left for testing.

redisLuaLocker.Lock(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 9/9
Construct(...) github.com/wfusion/gofusion/lock/construct.go 100.0% 7/7
mysqlLocker.isLocked(...) github.com/wfusion/gofusion/lock/mysql.go 100.0% 4/4
@31:9(...) github.com/wfusion/gofusion/lock/construct.go 100.0% 4/4
redisLuaLocker.Unlock(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 3/3
redisNXLocker.Unlock(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 2/2
@90:9(...) github.com/wfusion/gofusion/lock/construct.go 100.0% 1/1
Expire(...) github.com/wfusion/gofusion/lock/types.go 100.0% 1/1
redisNXLocker.formatLockKey(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/lock/construct.go 100.0% 1/1
@54:9(...) github.com/wfusion/gofusion/lock/types.go 100.0% 1/1
@72:8(...) github.com/wfusion/gofusion/lock/candy.go 100.0% 1/1
newRedisNXLocker(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/lock/construct.go 100.0% 1/1
redisLuaLocker.formatLockKey(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 1/1
@31:9(...) github.com/wfusion/gofusion/lock/candy.go 100.0% 1/1
ReentrantKey(...) github.com/wfusion/gofusion/lock/types.go 100.0% 1/1
newRedisLuaLocker(...) github.com/wfusion/gofusion/lock/redis.go 100.0% 1/1
mongoLocker.formatLockKey(...) github.com/wfusion/gofusion/lock/mongo.go 100.0% 1/1
newMysqlLocker(...) github.com/wfusion/gofusion/lock/mysql.go 100.0% 1/1
mysqlLocker.formatLockKey(...) github.com/wfusion/gofusion/lock/mysql.go 100.0% 1/1
@60:9(...) github.com/wfusion/gofusion/lock/types.go 100.0% 1/1
mongoLocker.Lock(...) github.com/wfusion/gofusion/lock/mongo.go 93.8% 15/16
redisNXLocker.Lock(...) github.com/wfusion/gofusion/lock/redis.go 91.7% 11/12
@30:19(...) github.com/wfusion/gofusion/lock/candy.go 91.7% 11/12
mongoLocker.Unlock(...) github.com/wfusion/gofusion/lock/mongo.go 91.7% 11/12
mysqlLocker.Unlock(...) github.com/wfusion/gofusion/lock/mysql.go 85.7% 6/7
mysqlLocker.Lock(...) github.com/wfusion/gofusion/lock/mysql.go 82.6% 19/23
addInstance(...) github.com/wfusion/gofusion/lock/construct.go 82.6% 19/23
Within(...) github.com/wfusion/gofusion/lock/candy.go 80.0% 16/20
Use(...) github.com/wfusion/gofusion/lock/construct.go 80.0% 8/10
redisLuaLocker.ReentrantLock(...) github.com/wfusion/gofusion/lock/redis.go 75.0% 3/4
mongoLocker.ReentrantLock(...) github.com/wfusion/gofusion/lock/mongo.go 75.0% 3/4
@70:3(...) github.com/wfusion/gofusion/lock/mysql.go 73.3% 11/15
newMongoLocker(...) github.com/wfusion/gofusion/lock/mongo.go 70.6% 12/17
UseReentrant(...) github.com/wfusion/gofusion/lock/construct.go 0.0% 0/13
@78:5(...) github.com/wfusion/gofusion/lock/construct.go 0.0% 0/1
@75:22(...) github.com/wfusion/gofusion/lock/construct.go 0.0% 0/1
func redisLuaLocker.Lock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

58
func (r *redisLuaLocker) Lock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
59
        opt := utils.ApplyOptions[lockOption](opts...)
60
        expired := tolerance
61
        if opt.expired > 0 {
62
                expired = opt.expired
63
        }
64
        lockKey := r.formatLockKey(key)
65
        err = redis.
66
                Use(ctx, r.redisName, redis.AppName(r.appName)).
67
                Eval(ctx, redisLuaLockCommand, []string{lockKey}, []string{
68
                        opt.reentrantKey, strconv.Itoa(int(expired / time.Millisecond)),
69
                }).
70
                Err()
71
        if errors.Is(err, rdsDrv.Nil) {
72
                return ErrTimeout
73
        }
74
        return
75
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

21
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
22
        opt := utils.ApplyOptions[config.InitOption](opts...)
23
        optU := utils.ApplyOptions[useOption](opts...)
24
        if opt.AppName == "" {
25
                opt.AppName = optU.appName
26
        }
27
        for name, conf := range confs {
28
                addInstance(ctx, name, conf, opt)
29
        }
30
31
        return func() {
32
                rwlock.Lock()
33
                defer rwlock.Unlock()
34
                if appInstances != nil {
35
                        delete(appInstances, opt.AppName)
36
                }
37
        }
38
}
func mysqlLocker.isLocked
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

112
func (m *mysqlLocker) isLocked(ctx context.Context, lockKey string) (locked bool) {
113
        m.locker.RLock()
114
        defer m.locker.RUnlock()
115
        _, locked = m.lockTimers[lockKey]
116
        return
117
}
func @31:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

31
func() {
32
                rwlock.Lock()
33
                defer rwlock.Unlock()
34
                if appInstances != nil {
35
                        delete(appInstances, opt.AppName)
36
                }
37
        }
func redisLuaLocker.Unlock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

77
func (r *redisLuaLocker) Unlock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
78
        opt := utils.ApplyOptions[lockOption](opts...)
79
        lockKey := r.formatLockKey(key)
80
        return redis.
81
                Use(ctx, r.redisName, redis.AppName(r.appName)).
82
                Eval(ctx, redisLuaUnlockCommand, []string{lockKey}, []string{opt.reentrantKey}).
83
                Err()
84
}
func redisNXLocker.Unlock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

127
func (r *redisNXLocker) Unlock(ctx context.Context, key string, _ ...utils.OptionExtender) (err error) {
128
        lockKey := r.formatLockKey(key)
129
        return redis.Use(ctx, r.redisName, redis.AppName(r.appName)).Del(ctx, lockKey).Err()
130
}
func @90:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

90
func(o *useOption) {
91
                o.appName = name
92
        }
func Expire
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/types.go:

53
func Expire(expired time.Duration) utils.OptionFunc[lockOption] {
54
        return func(l *lockOption) {
55
                l.expired = expired
56
        }
57
}
func redisNXLocker.formatLockKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

132
func (r *redisNXLocker) formatLockKey(key string) (format string) {
133
        return fmt.Sprintf("%s:%s", config.Use(r.appName).AppName(), key)
134
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

89
func AppName(name string) utils.OptionFunc[useOption] {
90
        return func(o *useOption) {
91
                o.appName = name
92
        }
93
}
func @54:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/types.go:

54
func(l *lockOption) {
55
                l.expired = expired
56
        }
func @72:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/candy.go:

72
func() { err = multierr.Append(err, locker.Unlock(ctx, key, optionals...)) }
func newRedisNXLocker
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

105
func newRedisNXLocker(ctx context.Context, appName, redisName string) Lockable {
106
        return &redisNXLocker{ctx: ctx, appName: appName, redisName: redisName}
107
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

132
func init() {
133
        config.AddComponent(config.ComponentLock, Construct)
134
}
func redisLuaLocker.formatLockKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

95
func (r *redisLuaLocker) formatLockKey(key string) (format string) {
96
        return fmt.Sprintf("%s:%s", config.Use(r.appName).AppName(), key)
97
}
func @31:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/candy.go:

31
func() { done <- struct{}{} }
func ReentrantKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/types.go:

59
func ReentrantKey(key string) utils.OptionFunc[lockOption] {
60
        return func(l *lockOption) {
61
                l.reentrantKey = key
62
        }
63
}
func newRedisLuaLocker
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

54
func newRedisLuaLocker(ctx context.Context, appName, redisName string) ReentrantLockable {
55
        return &redisLuaLocker{ctx: ctx, appName: appName, redisName: redisName}
56
}
func mongoLocker.formatLockKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mongo.go:

153
func (m *mongoLocker) formatLockKey(key string) (format string) {
154
        return fmt.Sprintf("%s_%s", config.Use(m.appName).AppName(), key)
155
}
func newMysqlLocker
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

32
func newMysqlLocker(ctx context.Context, appName, dbName string) Lockable {
33
        return &mysqlLocker{ctx: ctx, appName: appName, dbName: dbName, lockTimers: map[string]struct{}{}}
34
}
func mysqlLocker.formatLockKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

119
func (m *mysqlLocker) formatLockKey(key string) string {
120
        return fmt.Sprintf("%s:%s", config.Use(m.appName).AppName(), key)
121
}
func @60:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/types.go:

60
func(l *lockOption) {
61
                l.reentrantKey = key
62
        }
func mongoLocker.Lock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mongo.go:

71
func (m *mongoLocker) Lock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
72
        opt := utils.ApplyOptions[lockOption](opts...)
73
        expired := tolerance
74
        if opt.expired > 0 {
75
                expired = opt.expired
76
        }
77
        now := time.Now()
78
        lockKey := m.formatLockKey(key)
79
        filter := bson.M{
80
                "lock_key": bson.M{"$eq": lockKey, "$exists": true},
81
                "$or": []bson.M{
82
                        {"expires_at": bson.M{"$lt": now, "$exists": true}},
83
                        {"holder": bson.M{"$eq": opt.reentrantKey, "$exists": true}},
84
                },
85
        }
86
        update := bson.M{
87
                "$setOnInsert": bson.M{
88
                        "lock_key": lockKey,
89
                        "holder":   opt.reentrantKey,
90
                },
91
                "$inc": bson.M{"count": 1},
92
                "$max": bson.M{"expires_at": now.Add(expired)},
93
        }
94
        mopts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)
95
96
        updatedDoc := new(mongoLockDoc)
97
        err = mongo.Use(m.mongoName, mongo.AppName(m.appName), mongo.WriteConcern(writeconcern.Majority())).
98
                Collection(m.collName).
99
                FindOneAndUpdate(ctx, filter, update, mopts).
100
                Decode(updatedDoc)
101
        if err != nil {
102
                return
103
        }
104
105
        if updatedDoc.LockKey == lockKey && updatedDoc.Holder == opt.reentrantKey {
106
                return
107
        }
108
109
        return ErrTimeout
110
}
func redisNXLocker.Lock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

109
func (r *redisNXLocker) Lock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
110
        opt := utils.ApplyOptions[lockOption](opts...)
111
        expired := tolerance
112
        if opt.expired > 0 {
113
                expired = opt.expired
114
        }
115
        lockKey := r.formatLockKey(key)
116
        cmd := redis.Use(ctx, r.redisName, redis.AppName(r.appName)).SetNX(ctx, lockKey, utils.UUID(), expired)
117
        if err = cmd.Err(); err != nil {
118
                return
119
        }
120
        if !cmd.Val() {
121
                err = ErrTimeout
122
                return
123
        }
124
        return
125
}
func @30:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/candy.go:

30
func() {
31
                defer func() { done <- struct{}{} }()
32
33
                var e error
34
                rLocker, ok := locker.(ReentrantLockable)
35
                for {
36
                        select {
37
                        case <-timeFault: // timeout exit
38
                                return
39
                        default:
40
                                if ok {
41
                                        if e = rLocker.ReentrantLock(ctx, key, optL.reentrantKey, optionals...); e == nil {
42
                                                return
43
                                        }
44
                                } else {
45
                                        if e = locker.Lock(ctx, key, optionals...); e == nil {
46
                                                return
47
                                        }
48
                                }
49
50
                                // relock after 200 milliseconds
51
                                time.Sleep(reLockWaitTime)
52
                        }
53
                }
54
        }
func mongoLocker.Unlock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mongo.go:

112
func (m *mongoLocker) Unlock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
113
        opt := utils.ApplyOptions[lockOption](opts...)
114
        filter := bson.M{
115
                "lock_key": m.formatLockKey(key),
116
                "holder":   opt.reentrantKey,
117
                "count":    bson.M{"$gt": 0},
118
        }
119
        update := bson.M{
120
                "$inc": bson.M{"count": -1},
121
                "$max": bson.M{"expires_at": time.Now().Add(opt.expired / 2)},
122
        }
123
        mopts := options.FindOneAndUpdate().SetReturnDocument(options.After)
124
125
        updatedDoc := new(mongoLockDoc)
126
        coll := mongo.
127
                Use(m.mongoName, mongo.AppName(m.appName), mongo.WriteConcern(writeconcern.Majority())).
128
                Collection(m.collName)
129
        err = coll.FindOneAndUpdate(ctx, filter, update, mopts).Decode(&updatedDoc)
130
        if err != nil {
131
                return
132
        }
133
        if updatedDoc.Count <= 0 {
134
                _, err = coll.DeleteOne(ctx, bson.M{
135
                        "lock_key": m.formatLockKey(key),
136
                        "holder":   opt.reentrantKey,
137
                        "count":    bson.M{"$lte": 0},
138
                })
139
        }
140
141
        return
142
}
func mysqlLocker.Unlock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

100
func (m *mysqlLocker) Unlock(ctx context.Context, key string, _ ...utils.OptionExtender) (err error) {
101
        lockKey := m.formatLockKey(key)
102
        if err = db.Use(ctx, m.dbName, db.AppName(m.appName)).Raw(mysqlUnlockSQL, lockKey).Error; err != nil {
103
                return
104
        }
105
        m.locker.Lock()
106
        defer m.locker.Unlock()
107
        delete(m.lockTimers, lockKey)
108
109
        return
110
}
func mysqlLocker.Lock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

36
func (m *mysqlLocker) Lock(ctx context.Context, key string, opts ...utils.OptionExtender) (err error) {
37
        opt := utils.ApplyOptions[lockOption](opts...)
38
        expired := tolerance
39
        if opt.expired > 0 {
40
                expired = opt.expired
41
        }
42
        lockKey := m.formatLockKey(key)
43
        if len(lockKey) > 64 {
44
                return errors.Errorf("key %s length is too long, max key length is 64", lockKey)
45
        }
46
47
        m.locker.Lock()
48
        defer m.locker.Unlock()
49
        // disable reentrant
50
        if _, ok := m.lockTimers[lockKey]; ok {
51
                return ErrTimeout
52
        }
53
54
        ret := db.Use(ctx, m.dbName, db.AppName(m.appName)).Raw(mysqlLockSQL, lockKey, 0)
55
        if err = ret.Error; err != nil {
56
                return ret.Error
57
        }
58
        var result int64
59
        if err = ret.Scan(&result).Error; err != nil {
60
                return
61
        }
62
        if result != 1 {
63
                return ErrTimeout
64
        }
65
66
        // expire loop
67
        m.lockTimers[lockKey] = struct{}{}
68
        timer := time.NewTimer(expired)
69
        routine.Loop(
70
                func(ctx context.Context, key string, timer *time.Timer) {
71
                        defer timer.Stop()
72
73
                        lockKey := m.formatLockKey(key)
74
                        if !m.isLocked(ctx, lockKey) {
75
                                return
76
                        }
77
78
                        for {
79
                                select {
80
                                case <-ctx.Done():
81
                                        _ = m.Unlock(ctx, key) // context done
82
                                        return
83
                                case <-m.ctx.Done():
84
                                        _ = m.Unlock(ctx, key) // context done
85
                                        return
86
                                case <-timer.C:
87
                                        _ = m.Unlock(ctx, key) // timeout
88
                                        return
89
                                default:
90
                                        if !m.isLocked(ctx, lockKey) {
91
                                                return
92
                                        }
93
                                        time.Sleep(200*time.Millisecond + time.Duration(rand.Int63())%(100*time.Millisecond))
94
                                }
95
                        }
96
                }, routine.Args(ctx, key, timer), routine.AppName(m.appName))
97
        return
98
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

40
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
41
        rwlock.Lock()
42
        defer rwlock.Unlock()
43
        if appInstances == nil {
44
                appInstances = make(map[string]map[string]Lockable)
45
        }
46
        if appInstances[opt.AppName] == nil {
47
                appInstances[opt.AppName] = make(map[string]Lockable)
48
        }
49
50
        if _, ok := appInstances[opt.AppName][name]; ok {
51
                panic(ErrDuplicatedName)
52
        }
53
54
        switch conf.Type {
55
        case lockTypeRedisLua:
56
                redis.Use(ctx, conf.Instance, redis.AppName(opt.AppName)) // check if instance exists
57
                appInstances[opt.AppName][name] = newRedisLuaLocker(ctx, opt.AppName, conf.Instance)
58
        case lockTypeRedisNX:
59
                redis.Use(ctx, conf.Instance, redis.AppName(opt.AppName)) // check if instance exists
60
                appInstances[opt.AppName][name] = newRedisNXLocker(ctx, opt.AppName, conf.Instance)
61
        case lockTypeMySQL:
62
                db.Use(ctx, conf.Instance, db.AppName(opt.AppName)) // check if instance exists
63
                appInstances[opt.AppName][name] = newMysqlLocker(ctx, opt.AppName, conf.Instance)
64
        case lockTypeMariaDB:
65
                db.Use(ctx, conf.Instance, db.AppName(opt.AppName)) // check if instance exists
66
                appInstances[opt.AppName][name] = newMysqlLocker(ctx, opt.AppName, conf.Instance)
67
        case lockTypeMongo:
68
                appInstances[opt.AppName][name] = newMongoLocker(ctx, opt.AppName, conf.Instance, conf.Scheme)
69
        default:
70
                panic(ErrUnsupportedLockType)
71
        }
72
73
        // ioc
74
        if opt.DI != nil {
75
                opt.DI.MustProvide(func() Lockable { return Use(name, AppName(opt.AppName)) }, di.Name(name))
76
                if _, ok := appInstances[opt.AppName][name].(ReentrantLockable); ok {
77
                        opt.DI.MustProvide(
78
                                func() ReentrantLockable { return UseReentrant(ctx, name, AppName(opt.AppName)) },
79
                                di.Name(name),
80
                        )
81
                }
82
        }
83
}
func Within
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/candy.go:

13
func Within(ctx context.Context, locker Lockable, key string,
14
        expired, timeout time.Duration, cb func() error, opts ...utils.OptionExtender) (err error) {
15
        const (
16
                reLockWaitTime = time.Duration(200) * time.Millisecond
17
        )
18
        opt := utils.ApplyOptions[useOption](opts...)
19
        optL := utils.ApplyOptions[lockOption](opts...)
20
        if optL.reentrantKey == "" {
21
                optL.reentrantKey = utils.ULID()
22
        }
23
        optionals := []utils.OptionExtender{ReentrantKey(optL.reentrantKey)}
24
        if expired > 0 {
25
                optionals = append(optionals, Expire(expired))
26
        }
27
28
        done := make(chan struct{}, 1)
29
        timeFault := make(chan struct{}, 1)
30
        routine.Goc(ctx, func() {
31
                defer func() { done <- struct{}{} }()
32
33
                var e error
34
                rLocker, ok := locker.(ReentrantLockable)
35
                for {
36
                        select {
37
                        case <-timeFault: // timeout exit
38
                                return
39
                        default:
40
                                if ok {
41
                                        if e = rLocker.ReentrantLock(ctx, key, optL.reentrantKey, optionals...); e == nil {
42
                                                return
43
                                        }
44
                                } else {
45
                                        if e = locker.Lock(ctx, key, optionals...); e == nil {
46
                                                return
47
                                        }
48
                                }
49
50
                                // relock after 200 milliseconds
51
                                time.Sleep(reLockWaitTime)
52
                        }
53
                }
54
        }, routine.AppName(opt.appName))
55
56
        timer := time.NewTimer(timeout)
57
        select {
58
        // success
59
        case <-done:
60
61
        // context done
62
        case <-ctx.Done():
63
                timeFault <- struct{}{}
64
                return ErrContextDone
65
66
        // timeout
67
        case <-timer.C:
68
                timeFault <- struct{}{}
69
                return ErrTimeout
70
        }
71
72
        defer func() { err = multierr.Append(err, locker.Unlock(ctx, key, optionals...)) }()
73
74
        _, err = utils.Catch(cb)
75
        return
76
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

95
func Use(name string, opts ...utils.OptionExtender) Lockable {
96
        opt := utils.ApplyOptions[useOption](opts...)
97
98
        rwlock.RLock()
99
        defer rwlock.RUnlock()
100
        instances, ok := appInstances[opt.appName]
101
        if !ok {
102
                panic(errors.Errorf("locker instance not found for app: %s", opt.appName))
103
        }
104
        instance, ok := instances[name]
105
        if !ok {
106
                panic(errors.Errorf("locker instance not found for name: %s", name))
107
        }
108
        return instance
109
}
func redisLuaLocker.ReentrantLock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/redis.go:

86
func (r *redisLuaLocker) ReentrantLock(ctx context.Context, key, reentrantKey string,
87
        opts ...utils.OptionExtender) (err error) {
88
        opt := utils.ApplyOptions[lockOption](opts...)
89
        if utils.IsStrBlank(opt.reentrantKey) {
90
                return ErrReentrantKeyNotFound
91
        }
92
        return r.Lock(ctx, key, append(opts, ReentrantKey(reentrantKey))...)
93
}
func mongoLocker.ReentrantLock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mongo.go:

144
func (m *mongoLocker) ReentrantLock(ctx context.Context, key, reentrantKey string,
145
        opts ...utils.OptionExtender) (err error) {
146
        opt := utils.ApplyOptions[lockOption](opts...)
147
        if utils.IsStrBlank(opt.reentrantKey) {
148
                return ErrReentrantKeyNotFound
149
        }
150
        return m.Lock(ctx, key, append(opts, ReentrantKey(reentrantKey))...)
151
}
func @70:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mysql.go:

70
func(ctx context.Context, key string, timer *time.Timer) {
71
                        defer timer.Stop()
72
73
                        lockKey := m.formatLockKey(key)
74
                        if !m.isLocked(ctx, lockKey) {
75
                                return
76
                        }
77
78
                        for {
79
                                select {
80
                                case <-ctx.Done():
81
                                        _ = m.Unlock(ctx, key) // context done
82
                                        return
83
                                case <-m.ctx.Done():
84
                                        _ = m.Unlock(ctx, key) // context done
85
                                        return
86
                                case <-timer.C:
87
                                        _ = m.Unlock(ctx, key) // timeout
88
                                        return
89
                                default:
90
                                        if !m.isLocked(ctx, lockKey) {
91
                                                return
92
                                        }
93
                                        time.Sleep(200*time.Millisecond + time.Duration(rand.Int63())%(100*time.Millisecond))
94
                                }
95
                        }
96
                }
func newMongoLocker
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/mongo.go:

32
func newMongoLocker(ctx context.Context, appName, mongoName, collName string) Lockable {
33
        mongoInitLocker.Lock()
34
        defer mongoInitLocker.Unlock()
35
36
        db := mongo.Use(mongoName, mongo.AppName(appName), mongo.WriteConcern(writeconcern.Majority()))
37
        coll := db.Collection(collName)
38
        colls, err := db.ListCollectionNames(ctx, bson.M{"name": collName})
39
        if err != nil {
40
                panic(errors.Errorf("%s lock component mongo %s parse collection %s failed: %s",
41
                        appName, mongoName, collName, err))
42
        }
43
        if len(colls) == 0 {
44
                if err = db.CreateCollection(ctx, collName); err != nil {
45
                        panic(errors.Errorf("%s lock component mongo %s create collection %s failed: %s",
46
                                appName, mongoName, collName, err))
47
                }
48
        }
49
50
        ttlIdxModel := mgoDrv.IndexModel{
51
                Keys:    bson.M{"expires_at": 1},
52
                Options: options.Index().SetExpireAfterSeconds(0),
53
        }
54
        if _, err = coll.Indexes().CreateOne(ctx, ttlIdxModel); err != nil {
55
                panic(errors.Errorf("%s lock component mongo %s create ttl index %s failed: %s",
56
                        appName, mongoName, collName, err))
57
        }
58
59
        indexModel := mgoDrv.IndexModel{
60
                Keys:    bson.M{"lock_key": 1},
61
                Options: options.Index().SetUnique(true),
62
        }
63
        if _, err = coll.Indexes().CreateOne(ctx, indexModel); err != nil {
64
                panic(errors.Errorf("%s lock component mongo %s create lock index %s failed: %s",
65
                        appName, mongoName, collName, err))
66
        }
67
68
        return &mongoLocker{ctx: ctx, appName: appName, mongoName: mongoName, collName: collName}
69
}
func UseReentrant
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

111
func UseReentrant(ctx context.Context, name string, opts ...utils.OptionExtender) ReentrantLockable {
112
        opt := utils.ApplyOptions[useOption](opts...)
113
114
        rwlock.RLock()
115
        defer rwlock.RUnlock()
116
        instances, ok := appInstances[opt.appName]
117
        if !ok {
118
                panic(errors.Errorf("reentrant locker instance not found for app: %s", opt.appName))
119
        }
120
        instance, ok := instances[name]
121
        if !ok {
122
                panic(errors.Errorf("reentrant locker instance not found for name: %s", name))
123
        }
124
        lockable, ok := instance.(ReentrantLockable)
125
        if !ok {
126
                panic(errors.Errorf("locker instance is not reentrantable: %s", name))
127
        }
128
129
        return lockable
130
}
func @78:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

78
func() ReentrantLockable { return UseReentrant(ctx, name, AppName(opt.AppName)) }
func @75:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/lock/construct.go:

75
func() Lockable { return Use(name, AppName(opt.AppName)) }
Package Overview: github.com/wfusion/gofusion/log 72.6%

Please select a function to see what's left for testing.

@40:9(...) github.com/wfusion/gofusion/log/construct.go 100.0% 11/11
logger.flush(...) github.com/wfusion/gofusion/log/logger.go 100.0% 6/6
getEncoderConfig(...) github.com/wfusion/gofusion/log/utils.go 100.0% 4/4
convertFieldsToZapFields(...) github.com/wfusion/gofusion/log/context.go 100.0% 4/4
zapLogLevel.Enabled(...) github.com/wfusion/gofusion/log/utils.go 100.0% 3/3
newZapLogLevel(...) github.com/wfusion/gofusion/log/utils.go 100.0% 3/3
@86:4(...) github.com/wfusion/gofusion/log/construct.go 100.0% 2/2
@87:4(...) github.com/wfusion/gofusion/log/construct.go 100.0% 2/2
GetCtxLogger(...) github.com/wfusion/gofusion/log/context.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/log/construct.go 100.0% 1/1
SetContextFields(...) github.com/wfusion/gofusion/log/candy.go 100.0% 1/1
@40:9(...) github.com/wfusion/gofusion/log/logger.go 100.0% 1/1
Info(...) github.com/wfusion/gofusion/log/candy.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/log/logger.go 100.0% 1/1
logger.sweeten(...) github.com/wfusion/gofusion/log/logger.go 90.9% 20/22
Construct(...) github.com/wfusion/gofusion/log/construct.go 90.0% 9/10
addInstance(...) github.com/wfusion/gofusion/log/construct.go 88.4% 38/43
defaultLogger(...) github.com/wfusion/gofusion/log/logger.go 85.7% 6/7
getContextZapFields(...) github.com/wfusion/gofusion/log/context.go 85.7% 6/7
zapLogLevel.reloadConfig(...) github.com/wfusion/gofusion/log/utils.go 80.0% 12/15
logger.Debug(...) github.com/wfusion/gofusion/log/logger.go 75.0% 3/4
logger.Warn(...) github.com/wfusion/gofusion/log/logger.go 75.0% 3/4
logger.Info(...) github.com/wfusion/gofusion/log/logger.go 75.0% 3/4
@138:12(...) github.com/wfusion/gofusion/log/logger.go 75.0% 3/4
getEncoder(...) github.com/wfusion/gofusion/log/utils.go 75.0% 3/4
Use(...) github.com/wfusion/gofusion/log/logger.go 62.5% 10/16
getLogLevel(...) github.com/wfusion/gofusion/log/utils.go 62.5% 5/8
@23:8(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/6
logger.Error(...) github.com/wfusion/gofusion/log/logger.go 0.0% 0/4
logger.Panic(...) github.com/wfusion/gofusion/log/logger.go 0.0% 0/4
logger.Fatal(...) github.com/wfusion/gofusion/log/logger.go 0.0% 0/4
@92:4(...) github.com/wfusion/gofusion/log/construct.go 0.0% 0/3
TimeElapsed(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/3
@88:4(...) github.com/wfusion/gofusion/log/construct.go 0.0% 0/2
Debug(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
GetContextFields(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
@157:4(...) github.com/wfusion/gofusion/log/construct.go 0.0% 0/1
SetCtxLogger(...) github.com/wfusion/gofusion/log/context.go 0.0% 0/1
Panic(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
Error(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
Warn(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
Fatal(...) github.com/wfusion/gofusion/log/candy.go 0.0% 0/1
func @40:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

40
func() {
41
                rwlock.Lock()
42
                defer rwlock.Unlock()
43
                if appInstances != nil {
44
                        for _, instance := range appInstances[opt.AppName] {
45
                                instance.flush()
46
                        }
47
                        delete(appInstances, opt.AppName)
48
                }
49
50
                // there maybe some locally logging, avoid some NPE crash as possible as we can do
51
                colorful := false
52
                if opt.AppName == "" {
53
                        if confs != nil && confs[config.DefaultInstanceKey] != nil {
54
                                colorful = confs[config.DefaultInstanceKey].ConsoleOutputOption.Colorful
55
                        }
56
                        globalLogger = defaultLogger(colorful)
57
                }
58
        }
func logger.flush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

137
func (l *logger) flush() {
138
        ignore := func(err error) bool {
139
                // ENOTTY:
140
                //     ignore sync /dev/stdout: inappropriate ioctl for device errors,
141
                //     which happens when redirect stderr to stdout
142
                // EINVAL:
143
                //     ignore sync /dev/stdout: invalid argument
144
                for _, target := range []error{syscall.EINVAL, syscall.ENOTTY} {
145
                        if errors.Is(err, target) {
146
                                return true
147
                        }
148
                }
149
                return false
150
        }
151
152
        pid := syscall.Getpid()
153
        if _, err := utils.Catch(l.logger.Sync); err != nil && !ignore(err) {
154
                log.Printf("%v [Gofusion] %s flush %s logger error: %s", pid, config.ComponentLog, l.name, err)
155
        }
156
        if _, err := utils.Catch(l.sugaredLogger.Sync); err != nil && !ignore(err) {
157
                log.Printf("%v [Gofusion] %s flush %s sugared logger error: %s",
158
                        pid, config.ComponentLog, l.name, err)
159
        }
160
}
func getEncoderConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

33
func getEncoderConfig(conf *Conf) zapcore.EncoderConfig {
34
        skips := make([]string, 0, len(encoder.SkipCallers)+len(conf.SkipCallers))
35
        skips = append(skips, encoder.SkipCallers...)
36
        skips = append(skips, conf.SkipCallers...)
37
        return zapcore.EncoderConfig{
38
                LevelKey:       "L",
39
                TimeKey:        "T",
40
                MessageKey:     "M",
41
                NameKey:        "N",
42
                CallerKey:      "C",
43
                StacktraceKey:  "S",
44
                LineEnding:     zapcore.DefaultLineEnding,
45
                EncodeLevel:    zapcore.CapitalLevelEncoder,
46
                EncodeTime:     zapcore.ISO8601TimeEncoder,
47
                EncodeDuration: zapcore.SecondsDurationEncoder,
48
                EncodeCaller:   encoder.SkipCallerEncoder(skips, conf.ShorterFilepath),
49
        }
50
}
func convertFieldsToZapFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/context.go:

27
func convertFieldsToZapFields(fields Fields) (zapFields []zap.Field) {
28
        zapFields = make([]zap.Field, 0, len(fields))
29
        for k, v := range fields {
30
                zapFields = append(zapFields, zap.Any(k, v))
31
        }
32
        return
33
}
func zapLogLevel.Enabled
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

85
func (z *zapLogLevel) Enabled(level zapcore.Level) bool {
86
        if z.reloadConfig(); !z.enabled {
87
                return false
88
        }
89
90
        return level >= z.Level
91
}
func newZapLogLevel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

63
func newZapLogLevel(appName, confName, enableField, levelField string) zapcore.LevelEnabler {
64
        z := &zapLogLevel{
65
                enabled:     true,
66
                appName:     config.Use(appName).AppName(),
67
                confName:    confName,
68
                enableField: enableField,
69
                levelField:  levelField,
70
        }
71
        z.reloadConfig()
72
        return z
73
}
func @86:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

86
func() bool { logName = conf.FileOutputOption.Name; return utils.IsStrNotBlank(logName) }
func @87:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

87
func() bool { logName = config.Use(opt.AppName).AppName() + ext; return utils.IsStrNotBlank(logName) }
func GetCtxLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/context.go:

35
func GetCtxLogger(ctx context.Context, args ...Loggable) (logger Loggable) {
36
        return utils.GetCtxAny(ctx, fusCtx.KeyLoggable, args...)
37
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

163
func init() {
164
        config.AddComponent(config.ComponentLog, Construct)
165
}
func SetContextFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

42
func SetContextFields(ctx context.Context, fields Fields) context.Context {
43
        return utils.SetCtxAny(ctx, fusCtx.KeyLogFields, fields)
44
}
func @40:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

40
func(o *useOption) {
41
                o.appName = name
42
        }
func Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

15
func Info(ctx context.Context, format string, args ...any)  { globalLogger.Info(ctx, format, args...) }
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

39
func AppName(name string) utils.OptionFunc[useOption] {
40
        return func(o *useOption) {
41
                o.appName = name
42
        }
43
}
func logger.sweeten
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

162
func (l *logger) sweeten(ctx context.Context, format string, raw ...any) (
163
        log Loggable, msg string, fields []zap.Field) {
164
        args := make([]any, 0, len(raw))
165
        fields = getContextZapFields(ctx)
166
        for _, arg := range raw {
167
                if f, ok := arg.(Fields); ok {
168
                        fields = append(fields, convertFieldsToZapFields(f)...)
169
                        continue
170
                }
171
                args = append(args, arg)
172
        }
173
174
        msg = fmt.Sprintf(format, args...)
175
        if userID := fusCtx.GetUserID(ctx); utils.IsStrNotBlank(userID) {
176
                fields = append(fields, zap.String("user_id", userID))
177
        }
178
        if traceID := fusCtx.GetTraceID(ctx); utils.IsStrNotBlank(traceID) {
179
                fields = append(fields, zap.String("trace_id", traceID))
180
        }
181
        if taskID := fusCtx.GetCronTaskID(ctx); utils.IsStrNotBlank(taskID) {
182
                fields = append(fields, zap.String("cron_task_id", taskID))
183
        }
184
        if taskName := fusCtx.GetCronTaskName(ctx); utils.IsStrNotBlank(taskName) {
185
                fields = append(fields, zap.String("cron_task_name", taskName))
186
        }
187
        if id := utils.GetCtxAny[string](ctx, watermill.ContextKeyMessageUUID); utils.IsStrNotBlank(id) {
188
                fields = append(fields, zap.String("message_uuid", id))
189
        }
190
        if id := utils.GetCtxAny[string](ctx, watermill.ContextKeyRawMessageID); utils.IsStrNotBlank(id) {
191
                fields = append(fields, zap.String("message_raw_id", id))
192
        }
193
194
        log = GetCtxLogger(ctx, l)
195
        return
196
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

24
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
25
        opt := utils.ApplyOptions[config.InitOption](opts...)
26
        optU := utils.ApplyOptions[useOption](opts...)
27
        if opt.AppName == "" {
28
                opt.AppName = optU.appName
29
        }
30
        for name, conf := range confs {
31
                addInstance(ctx, name, conf, opt)
32
        }
33
34
        if opt.AppName == "" && appInstances[opt.AppName] != nil {
35
                if conf, ok := appInstances[opt.AppName][config.DefaultInstanceKey]; !ok || conf == nil {
36
                        panic(ErrDefaultLoggerNotFound)
37
                }
38
        }
39
40
        return func() {
41
                rwlock.Lock()
42
                defer rwlock.Unlock()
43
                if appInstances != nil {
44
                        for _, instance := range appInstances[opt.AppName] {
45
                                instance.flush()
46
                        }
47
                        delete(appInstances, opt.AppName)
48
                }
49
50
                // there maybe some locally logging, avoid some NPE crash as possible as we can do
51
                colorful := false
52
                if opt.AppName == "" {
53
                        if confs != nil && confs[config.DefaultInstanceKey] != nil {
54
                                colorful = confs[config.DefaultInstanceKey].ConsoleOutputOption.Colorful
55
                        }
56
                        globalLogger = defaultLogger(colorful)
57
                }
58
        }
59
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

61
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
62
        if !conf.EnableFileOutput && !conf.EnableConsoleOutput {
63
                panic(ErrUnknownOutput)
64
        }
65
66
        var cores []zapcore.Core
67
        if conf.EnableConsoleOutput {
68
                cfg := getEncoderConfig(conf)
69
                if conf.ConsoleOutputOption.Colorful {
70
                        cfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
71
                }
72
                encoder := getEncoder(conf.ConsoleOutputOption.Layout, cfg)
73
                writer := zapcore.Lock(os.Stdout)
74
                logLevel := newZapLogLevel(opt.AppName, name, "enable_console_output", "log_level")
75
                cores = append(cores, zapcore.NewCore(encoder, writer, logLevel))
76
        }
77
        if conf.EnableFileOutput {
78
                var (
79
                        ext     = ".log"
80
                        logName string
81
                )
82
83
                cfg := getEncoderConfig(conf)
84
                encoder := getEncoder(conf.FileOutputOption.Layout, cfg)
85
                utils.IfAny(
86
                        func() bool { logName = conf.FileOutputOption.Name; return utils.IsStrNotBlank(logName) },
87
                        func() bool { logName = config.Use(opt.AppName).AppName() + ext; return utils.IsStrNotBlank(logName) },
88
                        func() bool {
89
                                logName = filepath.Base(env.WorkDir) + ext
90
                                return logName != constant.PathSeparator+".log"
91
                        },
92
                        func() bool {
93
                                sum := md5.Sum([]byte(env.WorkDir))
94
                                logName = string(sum[:]) + ext
95
                                return true
96
                        },
97
                )
98
99
                rotationSize, err := humanize.ParseBytes(conf.FileOutputOption.RotationSize)
100
                if err != nil {
101
                        panic(errors.Errorf("log component parse ratation size %s failed for name %s: %s",
102
                                conf.FileOutputOption.RotationSize, name, err))
103
                }
104
105
                maxAge, err := time.ParseDuration(conf.FileOutputOption.RotationMaxAge)
106
                if err != nil {
107
                        panic(errors.Errorf("log component parse ratation time %s failed for name %s: %s",
108
                                conf.FileOutputOption.RotationMaxAge, name, err))
109
                }
110
111
                writer := zapcore.AddSync(&rotatelog.Logger{
112
                        Filename:   path.Join(filepath.Clean(conf.FileOutputOption.Path), logName),
113
                        MaxSize:    int64(rotationSize),
114
                        MaxBackups: conf.FileOutputOption.RotationCount,
115
                        MaxAge:     maxAge,
116
                        Compress:   conf.FileOutputOption.Compress,
117
                })
118
                logLevel := newZapLogLevel(opt.AppName, name, "enable_file_output", "log_level")
119
                cores = append(cores, zapcore.NewCore(encoder, writer, logLevel))
120
        }
121
122
        zopts := []zap.Option{
123
                zap.Hooks(),
124
                zap.AddCaller(),
125
                zap.AddStacktrace(newZapLogLevel(opt.AppName, name, "enable_file_output", "stacktrace_level")),
126
        }
127
        if config.Use(opt.AppName).Debug() {
128
                zopts = append(zopts, zap.Development())
129
        }
130
131
        zapLogger := zap.
132
                New(zapcore.NewTee(cores...), zopts...).
133
                Named(config.Use(opt.AppName).AppName())
134
135
        fusLogger := &logger{name: name, logger: zapLogger, sugaredLogger: zapLogger.Sugar()}
136
137
        rwlock.Lock()
138
        defer rwlock.Unlock()
139
        if appInstances == nil {
140
                appInstances = make(map[string]map[string]*logger)
141
        }
142
        if appInstances[opt.AppName] == nil {
143
                appInstances[opt.AppName] = make(map[string]*logger)
144
        }
145
        if _, ok := appInstances[opt.AppName][name]; ok {
146
                panic(ErrDuplicatedName)
147
        }
148
        appInstances[opt.AppName][name] = fusLogger
149
150
        if opt.AppName == "" && name == config.DefaultInstanceKey {
151
                globalLogger = fusLogger
152
        }
153
154
        // ioc
155
        if opt.DI != nil {
156
                opt.DI.MustProvide(
157
                        func() Loggable { return Use(name, AppName(opt.AppName)) },
158
                        di.Name(name),
159
                )
160
        }
161
}
func defaultLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

72
func defaultLogger(colorful bool) Loggable {
73
        devCfg := zap.NewDevelopmentConfig()
74
        devCfg.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
75
        if colorful {
76
                devCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
77
        }
78
        devCfg.EncoderConfig.EncodeCaller = encoder.SkipCallerEncoder(encoder.SkipCallers, true)
79
        zapLogger, _ := devCfg.Build(
80
                zap.AddStacktrace(zap.PanicLevel),
81
                zap.AddCaller(),
82
                zap.Hooks(),
83
        )
84
        return &logger{
85
                logger:        zapLogger,
86
                sugaredLogger: zapLogger.Sugar(),
87
        }
88
}
func getContextZapFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/context.go:

15
func getContextZapFields(ctx context.Context) (zapFields []zap.Field) {
16
        v := ctx.Value(fusCtx.KeyLogFields)
17
        if v == nil {
18
                return
19
        }
20
        field, ok := v.(Fields)
21
        if !ok {
22
                return
23
        }
24
        return convertFieldsToZapFields(field)
25
}
func zapLogLevel.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

93
func (z *zapLogLevel) reloadConfig() {
94
        var cfgs map[string]map[string]any
95
        _ = config.Use(z.appName).LoadComponentConfig(config.ComponentLog, &cfgs)
96
        if len(cfgs) == 0 {
97
                return
98
        }
99
100
        cfg, ok := cfgs[z.confName]
101
        if !ok {
102
                return
103
        }
104
        enabled := cast.ToBool(cfg[z.enableField])
105
        z.enabled = enabled
106
107
        logLevelObj, ok1 := cfg[z.levelField]
108
        logLevel, ok2 := logLevelObj.(string)
109
        if !ok1 || !ok2 {
110
                return
111
        }
112
        level := getLogLevel(logLevel)
113
        z.Level = level
114
}
func logger.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

89
func (l *logger) Debug(ctx context.Context, format string, args ...any) {
90
        lg, msg, fields := l.sweeten(ctx, format, args...)
91
        if logger, ok := lg.(*logger); ok {
92
                logger.logger.Debug(msg, fields...)
93
        } else {
94
                lg.Debug(ctx, msg, args...)
95
        }
96
}
func logger.Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

105
func (l *logger) Warn(ctx context.Context, format string, args ...any) {
106
        lg, msg, fields := l.sweeten(ctx, format, args...)
107
        if logger, ok := lg.(*logger); ok {
108
                logger.logger.Warn(msg, fields...)
109
        } else {
110
                lg.Warn(ctx, msg, args...)
111
        }
112
}
func logger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

97
func (l *logger) Info(ctx context.Context, format string, args ...any) {
98
        lg, msg, fields := l.sweeten(ctx, format, args...)
99
        if logger, ok := lg.(*logger); ok {
100
                logger.logger.Info(msg, fields...)
101
        } else {
102
                lg.Info(ctx, msg, args...)
103
        }
104
}
func @138:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

138
func(err error) bool {
139
                // ENOTTY:
140
                //     ignore sync /dev/stdout: inappropriate ioctl for device errors,
141
                //     which happens when redirect stderr to stdout
142
                // EINVAL:
143
                //     ignore sync /dev/stdout: invalid argument
144
                for _, target := range []error{syscall.EINVAL, syscall.ENOTTY} {
145
                        if errors.Is(err, target) {
146
                                return true
147
                        }
148
                }
149
                return false
150
        }
func getEncoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

52
func getEncoder(layout string, cfg zapcore.EncoderConfig) zapcore.Encoder {
53
        switch strings.ToLower(layout) {
54
        case "json":
55
                return zapcore.NewJSONEncoder(cfg)
56
        case "console":
57
                return zapcore.NewConsoleEncoder(cfg)
58
        default:
59
                return zapcore.NewJSONEncoder(cfg)
60
        }
61
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

45
func Use(name string, opts ...utils.OptionExtender) Loggable {
46
        opt := utils.ApplyOptions[useOption](opts...)
47
48
        rwlock.RLock()
49
        defer rwlock.RUnlock()
50
        instances, ok := appInstances[opt.appName]
51
        if !ok {
52
                globalLogger.Debug(context.Background(), "%v [Gofusion] %s instance not found for app: %s",
53
                        syscall.Getpid(), config.ComponentLog, opt.appName, Fields{"component": "log"})
54
                return globalLogger
55
        }
56
        instance, ok := instances[name]
57
        if !ok {
58
                instance, ok = instances[config.DefaultInstanceKey]
59
                if ok {
60
                        instance.Debug(context.Background(), "%v [Gofusion] %s instance not found for name: %s",
61
                                syscall.Getpid(), config.ComponentLog, name, Fields{"component": "log"})
62
                        return instance
63
                }
64
                globalLogger.Debug(context.Background(), "%v [Gofusion] %s instance not found for name: %s",
65
                        syscall.Getpid(), config.ComponentLog, name, Fields{"component": "log"})
66
                return globalLogger
67
        }
68
69
        return instance
70
}
func getLogLevel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/utils.go:

14
func getLogLevel(level string) zapcore.Level {
15
        switch strings.ToLower(level) {
16
        case "debug":
17
                return zap.DebugLevel
18
        case "info":
19
                return zap.InfoLevel
20
        case "warn":
21
                return zap.WarnLevel
22
        case "error":
23
                return zap.ErrorLevel
24
        case "panic":
25
                return zap.PanicLevel
26
        case "fatal":
27
                return zap.FatalLevel
28
        default:
29
                return zap.InfoLevel
30
        }
31
}
func @23:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

23
func() {
24
                elapsed := time.Since(now).Milliseconds()
25
                if r := recover(); r != nil {
26
                        panic(r)
27
                }
28
                if logger != nil {
29
                        logger.Info(ctx, format, append(args, zap.Any("latency", elapsed))...)
30
                } else {
31
                        Info(ctx, format, append(args, zap.Any("latency", elapsed))...)
32
                }
33
        }
func logger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

113
func (l *logger) Error(ctx context.Context, format string, args ...any) {
114
        lg, msg, fields := l.sweeten(ctx, format, args...)
115
        if logger, ok := lg.(*logger); ok {
116
                logger.logger.Error(msg, fields...)
117
        } else {
118
                lg.Error(ctx, msg, args...)
119
        }
120
}
func logger.Panic
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

121
func (l *logger) Panic(ctx context.Context, format string, args ...any) {
122
        lg, msg, fields := l.sweeten(ctx, format, args...)
123
        if logger, ok := lg.(*logger); ok {
124
                logger.logger.Panic(msg, fields...)
125
        } else {
126
                lg.Panic(ctx, msg, args...)
127
        }
128
}
func logger.Fatal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/logger.go:

129
func (l *logger) Fatal(ctx context.Context, format string, args ...any) {
130
        lg, msg, fields := l.sweeten(ctx, format, args...)
131
        if logger, ok := lg.(*logger); ok {
132
                logger.logger.Fatal(msg, fields...)
133
        } else {
134
                lg.Fatal(ctx, msg, args...)
135
        }
136
}
func @92:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

92
func() bool {
93
                                sum := md5.Sum([]byte(env.WorkDir))
94
                                logName = string(sum[:]) + ext
95
                                return true
96
                        }
func TimeElapsed
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

21
func TimeElapsed(ctx context.Context, logger Loggable, fn func(), format string, args ...any) {
22
        now := time.Now()
23
        defer func() {
24
                elapsed := time.Since(now).Milliseconds()
25
                if r := recover(); r != nil {
26
                        panic(r)
27
                }
28
                if logger != nil {
29
                        logger.Info(ctx, format, append(args, zap.Any("latency", elapsed))...)
30
                } else {
31
                        Info(ctx, format, append(args, zap.Any("latency", elapsed))...)
32
                }
33
        }()
34
35
        fn()
36
}
func @88:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

88
func() bool {
89
                                logName = filepath.Base(env.WorkDir) + ext
90
                                return logName != constant.PathSeparator+".log"
91
                        }
func Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

14
func Debug(ctx context.Context, format string, args ...any) { globalLogger.Debug(ctx, format, args...) }
func GetContextFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

38
func GetContextFields(ctx context.Context) Fields {
39
        return utils.GetCtxAny(ctx, fusCtx.KeyLogFields, (Fields)(nil))
40
}
func @157:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/construct.go:

157
func() Loggable { return Use(name, AppName(opt.AppName)) }
func SetCtxLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/context.go:

39
func SetCtxLogger(ctx context.Context, val Loggable) context.Context {
40
        return utils.SetCtxAny(ctx, fusCtx.KeyLoggable, val)
41
}
func Panic
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

18
func Panic(ctx context.Context, format string, args ...any) { globalLogger.Panic(ctx, format, args...) }
func Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

17
func Error(ctx context.Context, format string, args ...any) { globalLogger.Error(ctx, format, args...) }
func Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

16
func Warn(ctx context.Context, format string, args ...any)  { globalLogger.Warn(ctx, format, args...) }
func Fatal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/candy.go:

19
func Fatal(ctx context.Context, format string, args ...any) { globalLogger.Fatal(ctx, format, args...) }
Package Overview: github.com/wfusion/gofusion/log/customlogger 59.2%

Please select a function to see what's left for testing.

gormLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 100.0% 5/5
mongoLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 5/5
asyncLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/async.go 100.0% 4/4
cronLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/cron.go 100.0% 4/4
metricsLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 100.0% 4/4
mqLogger.Debug(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 4/4
cronLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/cron.go 100.0% 4/4
mqLogger.Info(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 4/4
metricsLogger.Info(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 100.0% 4/4
redisLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 4/4
mqLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 4/4
metricsLogger.Warn(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 100.0% 4/4
mqLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 4/4
routineLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/routine.go 100.0% 3/3
mqLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 3/3
httpLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/http.go 100.0% 3/3
mongoLogger.succeeded(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 3/3
mongoLogger.pushCommandString(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 3/3
routineLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/routine.go 100.0% 3/3
cronLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/cron.go 100.0% 3/3
mongoLogger.started(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 3/3
httpLogger.Init(...) github.com/wfusion/gofusion/log/customlogger/http.go 100.0% 3/3
gormLogger.Info(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 100.0% 2/2
mongoLogger.fields(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 1/1
redisLogger.ProcessPipelineHook(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 1/1
mqLogger.With(...) github.com/wfusion/gofusion/log/customlogger/mq.go 100.0% 1/1
mongoLogger.GetMonitor(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 100.0% 1/1
DefaultCronLogger(...) github.com/wfusion/gofusion/log/customlogger/cron.go 100.0% 1/1
gormLogger.format(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 100.0% 1/1
gormLogger.fields(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 100.0% 1/1
redisLogger.DialHook(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 1/1
@41:9(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 1/1
redisLogger.ProcessHook(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 1/1
redisLogger.fields(...) github.com/wfusion/gofusion/log/customlogger/redis.go 100.0% 1/1
mongoLogger.popCommandString(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 85.7% 6/7
redisLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/redis.go 80.0% 12/15
mqLogger.parseLogFields(...) github.com/wfusion/gofusion/log/customlogger/mq.go 80.0% 8/10
mongoLogger.isLoggableCommandName(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 80.0% 4/5
gormLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 78.6% 11/14
metricsLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 77.8% 7/9
cronLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/cron.go 77.8% 7/9
asyncLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/async.go 77.8% 7/9
mqLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/mq.go 77.8% 7/9
mongoLogger.reloadConfig(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 75.0% 12/16
redisLogger.isLoggableCommandSet(...) github.com/wfusion/gofusion/log/customlogger/redis.go 75.0% 6/8
@45:9(...) github.com/wfusion/gofusion/log/customlogger/redis.go 75.0% 6/8
cronLogger.Debug(...) github.com/wfusion/gofusion/log/customlogger/cron.go 75.0% 3/4
asyncLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/async.go 75.0% 3/4
cronLogger.Info(...) github.com/wfusion/gofusion/log/customlogger/cron.go 75.0% 3/4
cronLogger.Warn(...) github.com/wfusion/gofusion/log/customlogger/cron.go 75.0% 3/4
asyncLogger.Info(...) github.com/wfusion/gofusion/log/customlogger/async.go 75.0% 3/4
mqLogger.Trace(...) github.com/wfusion/gofusion/log/customlogger/mq.go 75.0% 3/4
gormLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 75.0% 3/4
metricsLogger.Debug(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 75.0% 3/4
metricsLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 75.0% 3/4
redisLogger.isLoggable(...) github.com/wfusion/gofusion/log/customlogger/redis.go 75.0% 3/4
mongoLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 66.7% 2/3
metricsLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 66.7% 2/3
mongoLogger.failed(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 66.7% 2/3
cronLogger.Printf(...) github.com/wfusion/gofusion/log/customlogger/cron.go 66.7% 2/3
redisLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/redis.go 66.7% 2/3
gormLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 66.7% 2/3
asyncLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/async.go 66.7% 2/3
cronLogger.parseArgs(...) github.com/wfusion/gofusion/log/customlogger/cron.go 63.6% 14/22
asyncLogger.parseArgs(...) github.com/wfusion/gofusion/log/customlogger/async.go 63.6% 14/22
metricsLogger.parseArgs(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 54.5% 12/22
gormLogger.Trace(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 47.6% 10/21
gormLogger.getLogLevel(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 33.3% 2/6
httpLogger.Debugf(...) github.com/wfusion/gofusion/log/customlogger/http.go 33.3% 1/3
httpLogger.Errorf(...) github.com/wfusion/gofusion/log/customlogger/http.go 33.3% 1/3
@64:9(...) github.com/wfusion/gofusion/log/customlogger/redis.go 18.2% 2/11
httpLogger.parseArgs(...) github.com/wfusion/gofusion/log/customlogger/http.go 0.0% 0/14
routineLogger.parseArgs(...) github.com/wfusion/gofusion/log/customlogger/routine.go 0.0% 0/14
mqLogger.Error(...) github.com/wfusion/gofusion/log/customlogger/mq.go 0.0% 0/6
asyncLogger.Debug(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/4
asyncLogger.Warn(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/4
cronLogger.Error(...) github.com/wfusion/gofusion/log/customlogger/cron.go 0.0% 0/4
asyncLogger.Error(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/4
metricsLogger.Fatal(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 0.0% 0/4
cronLogger.Fatal(...) github.com/wfusion/gofusion/log/customlogger/cron.go 0.0% 0/4
asyncLogger.Fatal(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/4
metricsLogger.Error(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 0.0% 0/4
httpLogger.Warnf(...) github.com/wfusion/gofusion/log/customlogger/http.go 0.0% 0/3
metricsLogger.Printf(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 0.0% 0/3
DefaultMongoLogger(...) github.com/wfusion/gofusion/log/customlogger/mongo.go 0.0% 0/3
httpLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/http.go 0.0% 0/3
routineLogger.Printf(...) github.com/wfusion/gofusion/log/customlogger/routine.go 0.0% 0/3
asyncLogger.Printf(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/3
routineLogger.logger(...) github.com/wfusion/gofusion/log/customlogger/routine.go 0.0% 0/3
gormLogger.Error(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 0.0% 0/2
gormLogger.LogMode(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 0.0% 0/2
gormLogger.Warn(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 0.0% 0/2
DefaultHttpLogger(...) github.com/wfusion/gofusion/log/customlogger/http.go 0.0% 0/1
DefaultRoutineLogger(...) github.com/wfusion/gofusion/log/customlogger/routine.go 0.0% 0/1
DefaultAsyncLogger(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/1
DefaultAsynqAsyncLogger(...) github.com/wfusion/gofusion/log/customlogger/async.go 0.0% 0/1
DefaultMySQLLogger(...) github.com/wfusion/gofusion/log/customlogger/gorm.go 0.0% 0/1
NewLogger(...) github.com/wfusion/gofusion/log/customlogger/mq.go 0.0% 0/1
DefaultAsynqCronLogger(...) github.com/wfusion/gofusion/log/customlogger/cron.go 0.0% 0/1
DefaultMetricsLogger(...) github.com/wfusion/gofusion/log/customlogger/metrics.go 0.0% 0/1
func gormLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

112
func (g *gormLogger) Init(log log.Loggable, appName, name string) {
113
        g.log = log
114
        g.appName = appName
115
        g.confName = name
116
        g.ignoreRecordNotFoundError = true
117
        g.reloadConfig()
118
}
func mongoLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

75
func (m *mongoLogger) Init(log log.Loggable, appName, name string) {
76
        m.log = log
77
        m.appName = appName
78
        m.confName = name
79
        m.requestMap = make(map[int64]struct{ commandString string })
80
        m.loggableCommandSet = utils.NewSet[string](
81
                "ping",
82
                "insert",
83
                "find",
84
                "update",
85
                "delete",
86
                "aggregate",
87
                "distinct",
88
                "count",
89
                "findAndModify",
90
                "getMore",
91
                "killCursors",
92
                "create",
93
                "drop",
94
                "listDatabases",
95
                "dropDatabase",
96
                "createIndexes",
97
                "listIndexes",
98
                "dropIndexes",
99
                "listCollections",
100
        )
101
}
func asyncLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

36
func (a *asyncLogger) Init(log log.Loggable, appName, confName string) {
37
        a.log = log
38
        a.appName = appName
39
        a.confName = confName
40
        a.reloadConfig()
41
}
func cronLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

36
func (c *cronLogger) Init(log log.Loggable, appName, name string) {
37
        c.log = log
38
        c.appName = appName
39
        c.confName = name
40
        c.reloadConfig()
41
}
func metricsLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

32
func (m *metricsLogger) Init(log log.Loggable, appName, name string) {
33
        m.log = log
34
        m.appName = appName
35
        m.confName = name
36
        m.reloadConfig()
37
}
func mqLogger.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

66
func (m *mqLogger) Debug(msg string, fields watermill.LogFields) {
67
        if !m.isLoggable() {
68
                return
69
        }
70
        ctx, fs := m.parseLogFields(fields)
71
        m.logger().Debug(ctx, msg, fs)
72
}
func cronLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

140
func (c *cronLogger) isLoggable() bool {
141
        if c.confName == "" {
142
                return true
143
        }
144
        c.reloadConfig()
145
        return c.enabled
146
}
func mqLogger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

57
func (m *mqLogger) Info(msg string, fields watermill.LogFields) {
58
        if !m.isLoggable() {
59
                return
60
        }
61
        ctx, fs := m.parseLogFields(fields)
62
        m.logger().Info(ctx, msg, fs)
63
}
func metricsLogger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

56
func (m *metricsLogger) Info(args ...any) {
57
        if !m.isLoggable() {
58
                return
59
        }
60
        ctx, format, args := m.parseArgs(args...)
61
        m.logger().Info(ctx, format, args...)
62
}
func redisLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

33
func (r *redisLogger) Init(log log.Loggable, appName, name string) {
34
        r.log = log
35
        r.appName = appName
36
        r.confName = name
37
        r.reloadConfig()
38
}
func mqLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

111
func (m *mqLogger) isLoggable() bool {
112
        if m.confName == "" {
113
                return true
114
        }
115
116
        m.reloadConfig()
117
        return m.enabled
118
}
func metricsLogger.Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

65
func (m *metricsLogger) Warn(args ...any) {
66
        if !m.isLoggable() {
67
                return
68
        }
69
        ctx, format, args := m.parseArgs(args...)
70
        m.logger().Warn(ctx, format, args...)
71
}
func mqLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

36
func (m *mqLogger) Init(log log.Loggable, appName, name string) {
37
        m.log = log
38
        m.appName = appName
39
        m.confName = name
40
        m.reloadConfig()
41
}
func routineLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

77
func (r *routineLogger) reloadConfig() {
78
        cfg := make(map[string]any)
79
        _ = config.Use(r.appName).LoadComponentConfig(config.ComponentGoroutinePool, &cfg)
80
81
        r.enabled = cast.ToBool(cfg["enable_logger"])
82
}
func mqLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

88
func (m *mqLogger) logger() log.Loggable {
89
        if m.log != nil {
90
                return m.log
91
        }
92
        return log.Use(config.DefaultInstanceKey, log.AppName(m.appName))
93
}
func httpLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

87
func (h *httpLogger) reloadConfig() {
88
        cfg := make(map[string]any)
89
        _ = config.Use(h.appName).LoadComponentConfig(config.ComponentHttp, &cfg)
90
91
        h.enabled = cast.ToBool(cfg["enable_logger"])
92
}
func mongoLogger.succeeded
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

118
func (m *mongoLogger) succeeded(ctx context.Context, evt *event.CommandSucceededEvent) {
119
        if !m.isLoggableCommandName(evt.CommandName) {
120
                return
121
        }
122
        m.logger().Info(ctx, "%s succeeded: %s [request[%v] command[%s]]",
123
                evt.CommandName, evt.Reply, evt.RequestID, m.popCommandString(evt.RequestID),
124
                m.fields(log.Fields{"latency": int64(evt.Duration) / int64(time.Millisecond)}))
125
}
func mongoLogger.pushCommandString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

137
func (m *mongoLogger) pushCommandString(requestID int64, commandString string) {
138
        m.mutex.Lock()
139
        defer m.mutex.Unlock()
140
        m.requestMap[requestID] = struct{ commandString string }{commandString: commandString}
141
}
func routineLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

32
func (r *routineLogger) Init(log log.Loggable, appName string) {
33
        r.log = log
34
        r.appName = appName
35
        r.reloadConfig()
36
}
func cronLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

96
func (c *cronLogger) logger() log.Loggable {
97
        if c.log != nil {
98
                return c.log
99
        }
100
        return log.Use(config.DefaultInstanceKey, log.AppName(c.appName))
101
}
func mongoLogger.started
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

111
func (m *mongoLogger) started(ctx context.Context, evt *event.CommandStartedEvent) {
112
        if !m.isLoggableCommandName(evt.CommandName) {
113
                return
114
        }
115
        m.pushCommandString(evt.RequestID, evt.Command.String())
116
}
func httpLogger.Init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

30
func (h *httpLogger) Init(log log.Loggable, appName string) {
31
        h.log = log
32
        h.appName = appName
33
        h.reloadConfig()
34
}
func gormLogger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

52
func (g *gormLogger) Info(ctx context.Context, msg string, data ...any) {
53
        if g.isLoggable() && g.logLevel >= logger.Info {
54
                g.logger().Info(ctx, msg, append(data, dbFields)...)
55
        }
56
}
func mongoLogger.fields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

161
func (m *mongoLogger) fields(fields log.Fields) log.Fields {
162
        return utils.MapMerge(fields, mongoFields)
163
}
func redisLogger.ProcessPipelineHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

63
func (r *redisLogger) ProcessPipelineHook(next rdsDrv.ProcessPipelineHook) rdsDrv.ProcessPipelineHook {
64
        return func(ctx context.Context, cmds []rdsDrv.Cmder) (err error) {
65
                if !r.isLoggable() {
66
                        return next(ctx, cmds)
67
                }
68
                begin := time.Now()
69
                fullNameSb := new(strings.Builder)
70
                for _, cmd := range cmds {
71
                        _, _ = fullNameSb.WriteString(cmd.FullName() + " -> ")
72
                }
73
74
                if err = next(ctx, cmds); err != nil {
75
                        r.logger().Warn(ctx, "%s failed", fullNameSb.String(),
76
                                r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
77
                        return
78
                }
79
80
                r.logger().Info(ctx, "%s succeeded", fullNameSb.String(),
81
                        r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
82
                return
83
        }
84
}
func mqLogger.With
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

84
func (m *mqLogger) With(fields watermill.LogFields) watermill.LoggerAdapter {
85
        return &mqLogger{fields: m.fields.Add(fields)}
86
}
func mongoLogger.GetMonitor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

103
func (m *mongoLogger) GetMonitor() *event.CommandMonitor {
104
        return &event.CommandMonitor{
105
                Started:   m.started,
106
                Succeeded: m.succeeded,
107
                Failed:    m.failed,
108
        }
109
}
func DefaultCronLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

21
func DefaultCronLogger() interface{ Printf(string, ...any) } {
22
        return &cronLogger{}
23
}
func gormLogger.format
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

127
func (g *gormLogger) format(sql string) string {
128
        return strings.ReplaceAll(sql, "%", "%%")
129
}
func gormLogger.fields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

131
func (g *gormLogger) fields(fields log.Fields) log.Fields {
132
        return utils.MapMerge(fields, dbFields)
133
}
func redisLogger.DialHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

40
func (r *redisLogger) DialHook(next rdsDrv.DialHook) rdsDrv.DialHook {
41
        return func(ctx context.Context, network, addr string) (c net.Conn, e error) { return next(ctx, network, addr) }
42
}
func @41:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

41
func(ctx context.Context, network, addr string) (c net.Conn, e error) { return next(ctx, network, addr) }
func redisLogger.ProcessHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

44
func (r *redisLogger) ProcessHook(next rdsDrv.ProcessHook) rdsDrv.ProcessHook {
45
        return func(ctx context.Context, cmd rdsDrv.Cmder) (err error) {
46
                if !r.isLoggableCommandSet(cmd.Name()) {
47
                        return next(ctx, cmd)
48
                }
49
50
                begin := time.Now()
51
                if err = next(ctx, cmd); err != nil {
52
                        r.logger().Warn(ctx, "%s failed [command[%s]]", cmd.FullName(), cmd.String(),
53
                                r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
54
                        return
55
                }
56
57
                r.logger().Info(ctx, "%s succeeded [command[%s]]", cmd.FullName(), cmd.String(),
58
                        r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
59
                return
60
        }
61
}
func redisLogger.fields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

93
func (r *redisLogger) fields(fields log.Fields) log.Fields {
94
        return utils.MapMerge(fields, redisFields)
95
}
func mongoLogger.popCommandString
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

143
func (m *mongoLogger) popCommandString(requestID int64) string {
144
        m.mutex.Lock()
145
        defer m.mutex.Unlock()
146
        reqCtx, ok := m.requestMap[requestID]
147
        if ok {
148
                delete(m.requestMap, requestID)
149
                return reqCtx.commandString
150
        }
151
        return ""
152
}
func redisLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

120
func (r *redisLogger) reloadConfig() {
121
        var cfgs map[string]map[string]any
122
        _ = config.Use(r.appName).LoadComponentConfig(config.ComponentRedis, &cfgs)
123
        if len(cfgs) == 0 {
124
                return
125
        }
126
127
        cfg, ok := cfgs[r.confName]
128
        if !ok {
129
                return
130
        }
131
        enabled := cast.ToBool(cfg["enable_logger"])
132
        r.enabled = enabled
133
134
        unloggableCommandsObj, ok1 := cfg["unloggable_commands"]
135
        unloggableCommands, ok2 := unloggableCommandsObj.([]string)
136
        if !ok1 || !ok2 {
137
                return
138
        }
139
        sets := utils.NewSet(unloggableCommands...)
140
        r.unloggableCommandSet = sets
141
}
func mqLogger.parseLogFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

95
func (m *mqLogger) parseLogFields(fields watermill.LogFields) (ctx context.Context, fs log.Fields) {
96
        ctx = context.Background()
97
        fields = m.fields.Add(fields)
98
99
        fs = make(log.Fields, len(fields)+1)
100
        for k, v := range fields {
101
                if k == watermill.ContextLogFieldKey {
102
                        ctx = v.(context.Context)
103
                        continue
104
                }
105
                fs[k] = v
106
        }
107
        fs = utils.MapMerge(fs, mqFields)
108
        return
109
}
func mongoLogger.isLoggableCommandName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

165
func (m *mongoLogger) isLoggableCommandName(commandName string) bool {
166
        if m.confName == "" {
167
                return true
168
        }
169
        if m.reloadConfig(); !m.enabled {
170
                return false
171
        }
172
        return m.loggableCommandSet.Contains(commandName)
173
}
func gormLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

158
func (g *gormLogger) reloadConfig() {
159
        var cfgs map[string]map[string]any
160
        _ = config.Use(g.appName).LoadComponentConfig(config.ComponentDB, &cfgs)
161
        if len(cfgs) == 0 {
162
                return
163
        }
164
165
        cfg, ok := cfgs[g.confName]
166
        if !ok {
167
                return
168
        }
169
        g.enabled = cast.ToBool(cfg["enable_logger"])
170
        logConfigObj, ok1 := cfg["logger_config"]
171
        logCfg, ok2 := logConfigObj.(map[string]any)
172
        if !ok1 || !ok2 {
173
                return
174
        }
175
        g.logLevel = g.getLogLevel(cast.ToString(logCfg["log_level"]))
176
        g.slowThreshold, _ = time.ParseDuration(cast.ToString(logCfg["slow_threshold"]))
177
}
func metricsLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

144
func (m *metricsLogger) reloadConfig() {
145
        var cfgs map[string]map[string]any
146
        _ = config.Use(m.appName).LoadComponentConfig(config.ComponentMetrics, &cfgs)
147
        if len(cfgs) == 0 {
148
                return
149
        }
150
151
        cfg, ok := cfgs[m.confName]
152
        if !ok {
153
                return
154
        }
155
        enabled := cast.ToBool(cfg["enable_logger"])
156
        m.enabled = enabled
157
}
func cronLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

148
func (c *cronLogger) reloadConfig() {
149
        var cfgs map[string]map[string]any
150
        _ = config.Use(c.appName).LoadComponentConfig(config.ComponentCron, &cfgs)
151
        if len(cfgs) == 0 {
152
                return
153
        }
154
155
        cfg, ok := cfgs[c.confName]
156
        if !ok {
157
                return
158
        }
159
        enabled := cast.ToBool(cfg["enable_logger"])
160
        c.enabled = enabled
161
}
func asyncLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

148
func (a *asyncLogger) reloadConfig() {
149
        var cfgs map[string]map[string]any
150
        _ = config.Use(a.appName).LoadComponentConfig(config.ComponentAsync, &cfgs)
151
        if len(cfgs) == 0 {
152
                return
153
        }
154
155
        cfg, ok := cfgs[a.confName]
156
        if !ok {
157
                return
158
        }
159
        enabled := cast.ToBool(cfg["enable_logger"])
160
        a.enabled = enabled
161
}
func mqLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

120
func (m *mqLogger) reloadConfig() {
121
        var cfgs map[string]map[string]any
122
        _ = config.Use(m.appName).LoadComponentConfig(config.ComponentMessageQueue, &cfgs)
123
        if len(cfgs) == 0 {
124
                return
125
        }
126
127
        cfg, ok := cfgs[m.confName]
128
        if !ok {
129
                return
130
        }
131
        enabled := cast.ToBool(cfg["enable_logger"])
132
        m.enabled = enabled
133
}
func mongoLogger.reloadConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

175
func (m *mongoLogger) reloadConfig() {
176
        var cfgs map[string]map[string]any
177
        _ = config.Use(m.appName).LoadComponentConfig(config.ComponentMongo, &cfgs)
178
        if len(cfgs) == 0 {
179
                return
180
        }
181
182
        cfg, ok := cfgs[m.confName]
183
        if !ok {
184
                return
185
        }
186
        m.enabled = cast.ToBool(cfg["enable_logger"])
187
        logConfigObj, ok1 := cfg["logger_config"]
188
        logCfg, ok2 := logConfigObj.(map[string]any)
189
        if !ok1 || !ok2 {
190
                return
191
        }
192
        loggableCommandList, ok := logCfg["loggable_commands"].([]string)
193
        if !ok {
194
                return
195
        }
196
197
        m.loggableCommandSet = utils.NewSet(loggableCommandList...)
198
}
func redisLogger.isLoggableCommandSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

97
func (r *redisLogger) isLoggableCommandSet(command string) bool {
98
        if r.confName == "" {
99
                return true
100
        }
101
102
        r.reloadConfig()
103
        if !r.enabled {
104
                return false
105
        }
106
        if r.unloggableCommandSet == nil {
107
                return true
108
        }
109
        return !r.unloggableCommandSet.Contains(command)
110
}
func @45:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

45
func(ctx context.Context, cmd rdsDrv.Cmder) (err error) {
46
                if !r.isLoggableCommandSet(cmd.Name()) {
47
                        return next(ctx, cmd)
48
                }
49
50
                begin := time.Now()
51
                if err = next(ctx, cmd); err != nil {
52
                        r.logger().Warn(ctx, "%s failed [command[%s]]", cmd.FullName(), cmd.String(),
53
                                r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
54
                        return
55
                }
56
57
                r.logger().Info(ctx, "%s succeeded [command[%s]]", cmd.FullName(), cmd.String(),
58
                        r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
59
                return
60
        }
func cronLogger.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

51
func (c *cronLogger) Debug(args ...any) {
52
        if !c.isLoggable() {
53
                return
54
        }
55
        ctx, format, args := c.parseArgs(args...)
56
        c.logger().Debug(ctx, format, args...)
57
}
func asyncLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

140
func (a *asyncLogger) isLoggable() bool {
141
        if a.confName == "" {
142
                return true
143
        }
144
        a.reloadConfig()
145
        return a.enabled
146
}
func cronLogger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

60
func (c *cronLogger) Info(args ...any) {
61
        if !c.isLoggable() {
62
                return
63
        }
64
        ctx, format, args := c.parseArgs(args...)
65
        c.logger().Info(ctx, format, args...)
66
}
func cronLogger.Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

69
func (c *cronLogger) Warn(args ...any) {
70
        if !c.isLoggable() {
71
                return
72
        }
73
        ctx, format, args := c.parseArgs(args...)
74
        c.logger().Warn(ctx, format, args...)
75
}
func asyncLogger.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

60
func (a *asyncLogger) Info(args ...any) {
61
        if !a.isLoggable() {
62
                return
63
        }
64
        ctx, format, args := a.parseArgs(args...)
65
        a.logger().Info(ctx, format, args...)
66
}
func mqLogger.Trace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

75
func (m *mqLogger) Trace(msg string, fields watermill.LogFields) {
76
        if !m.isLoggable() {
77
                return
78
        }
79
        ctx, fs := m.parseLogFields(fields)
80
        m.logger().Debug(ctx, msg, fs)
81
}
func gormLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

150
func (g *gormLogger) isLoggable() bool {
151
        if g.confName == "" {
152
                return true
153
        }
154
        g.reloadConfig()
155
        return g.enabled
156
}
func metricsLogger.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

47
func (m *metricsLogger) Debug(args ...any) {
48
        if !m.isLoggable() {
49
                return
50
        }
51
        ctx, format, args := m.parseArgs(args...)
52
        m.logger().Debug(ctx, format, args...)
53
}
func metricsLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

136
func (m *metricsLogger) isLoggable() bool {
137
        if m.confName == "" {
138
                return true
139
        }
140
        m.reloadConfig()
141
        return m.enabled
142
}
func redisLogger.isLoggable
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

112
func (r *redisLogger) isLoggable() bool {
113
        if r.confName == "" {
114
                return true
115
        }
116
        r.reloadConfig()
117
        return r.enabled
118
}
func mongoLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

154
func (m *mongoLogger) logger() log.Loggable {
155
        if m.log != nil {
156
                return m.log
157
        }
158
        return log.Use(config.DefaultInstanceKey, log.AppName(m.appName))
159
}
func metricsLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

92
func (m *metricsLogger) logger() log.Loggable {
93
        if m.log != nil {
94
                return m.log
95
        }
96
        return log.Use(config.DefaultInstanceKey, log.AppName(m.appName))
97
}
func mongoLogger.failed
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

127
func (m *mongoLogger) failed(ctx context.Context, evt *event.CommandFailedEvent) {
128
        if !m.isLoggableCommandName(evt.CommandName) {
129
                return
130
        }
131
132
        m.logger().Warn(ctx, "%s failed: %s [request[%v] command[%s]]",
133
                evt.CommandName, evt.Failure, evt.RequestID, m.popCommandString(evt.RequestID),
134
                m.fields(log.Fields{"latency": int64(evt.Duration) / int64(time.Millisecond)}))
135
}
func cronLogger.Printf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

43
func (c *cronLogger) Printf(format string, args ...any) {
44
        if !c.isLoggable() {
45
                return
46
        }
47
        c.logger().Info(context.Background(), format, append(args, cronFields)...)
48
}
func redisLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

86
func (r *redisLogger) logger() log.Loggable {
87
        if r.log != nil {
88
                return r.log
89
        }
90
        return log.Use(config.DefaultInstanceKey, log.AppName(r.appName))
91
}
func gormLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

120
func (g *gormLogger) logger() log.Loggable {
121
        if g.log != nil {
122
                return g.log
123
        }
124
        return log.Use(config.DefaultInstanceKey, log.AppName(g.appName))
125
}
func asyncLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

96
func (a *asyncLogger) logger() log.Loggable {
97
        if a.log != nil {
98
                return a.log
99
        }
100
        return log.Use(config.DefaultInstanceKey, log.AppName(a.appName))
101
}
func cronLogger.parseArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

104
func (c *cronLogger) parseArgs(args ...any) (ctx context.Context, format string, params []any) {
105
        var ok bool
106
107
        if len(args) == 0 {
108
                return context.Background(), "", []any{cronFields}
109
        }
110
        if len(args) == 1 {
111
                args = append(args, cronFields)
112
                return context.Background(), "%+v", args
113
        }
114
115
        format, ok = args[0].(string)
116
        if ok {
117
                params = args[1:]
118
        } else {
119
                ctx, _ = args[0].(context.Context)
120
                format, _ = args[1].(string)
121
                params = args[2:]
122
        }
123
        if format == "" {
124
                placeholder := make([]string, len(args))
125
                for i := 0; i < len(args); i++ {
126
                        placeholder[i] = "%+v"
127
                }
128
                format = strings.Join(placeholder, " ")
129
                params = args
130
        }
131
132
        if ctx == nil {
133
                ctx = context.Background()
134
        }
135
136
        params = append(params, cronFields)
137
        return
138
}
func asyncLogger.parseArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

104
func (a *asyncLogger) parseArgs(args ...any) (ctx context.Context, format string, params []any) {
105
        var ok bool
106
107
        if len(args) == 0 {
108
                return context.Background(), "", []any{asyncFields}
109
        }
110
        if len(args) == 1 {
111
                args = append(args, asyncFields)
112
                return context.Background(), "%+v", args
113
        }
114
115
        format, ok = args[0].(string)
116
        if ok {
117
                params = args[1:]
118
        } else {
119
                ctx, _ = args[0].(context.Context)
120
                format, _ = args[1].(string)
121
                params = args[2:]
122
        }
123
        if format == "" {
124
                placeholder := make([]string, len(args))
125
                for i := 0; i < len(args); i++ {
126
                        placeholder[i] = "%+v"
127
                }
128
                format = strings.Join(placeholder, " ")
129
                params = args
130
        }
131
132
        if ctx == nil {
133
                ctx = context.Background()
134
        }
135
136
        params = append(params, asyncFields)
137
        return
138
}
func metricsLogger.parseArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

100
func (m *metricsLogger) parseArgs(args ...any) (ctx context.Context, format string, params []any) {
101
        var ok bool
102
103
        if len(args) == 0 {
104
                return context.Background(), "", []any{metricsFields}
105
        }
106
        if len(args) == 1 {
107
                args = append(args, metricsFields)
108
                return context.Background(), "%+v", args
109
        }
110
111
        format, ok = args[0].(string)
112
        if ok {
113
                params = args[1:]
114
        } else {
115
                ctx, _ = args[0].(context.Context)
116
                format, _ = args[1].(string)
117
                params = args[2:]
118
        }
119
        if format == "" {
120
                placeholder := make([]string, len(args))
121
                for i := 0; i < len(args); i++ {
122
                        placeholder[i] = "%+v"
123
                }
124
                format = strings.Join(placeholder, " ")
125
                params = args
126
        }
127
128
        if ctx == nil {
129
                ctx = context.Background()
130
        }
131
132
        params = append(params, metricsFields)
133
        return
134
}
func gormLogger.Trace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

73
func (g *gormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
74
        if !g.isLoggable() {
75
                return
76
        }
77
        if g.logLevel <= logger.Silent {
78
                return
79
        }
80
81
        elapsed := time.Since(begin)
82
        switch {
83
        case err != nil && g.logLevel >= logger.Error &&
84
                (!errors.Is(err, gorm.ErrRecordNotFound) || !g.ignoreRecordNotFoundError):
85
                sql, rows := fc()
86
                sql = fmt.Sprintf("err[%%s] %s", sql)
87
                if rows == -1 {
88
                        g.logger().Info(ctx, sql, err.Error(), g.fields(log.Fields{"latency": elapsed.Milliseconds()}))
89
                } else {
90
                        g.logger().Info(ctx, sql, err.Error(),
91
                                g.fields(log.Fields{"rows": rows, "latency": elapsed.Milliseconds()}))
92
                }
93
        case elapsed > g.slowThreshold && g.slowThreshold != 0 && g.logLevel >= logger.Warn:
94
                sql, rows := fc()
95
                slowLog := fmt.Sprintf("SLOW SQL >= %v %s", g.slowThreshold, g.format(sql))
96
                if rows == -1 {
97
                        g.logger().Info(ctx, slowLog, g.fields(log.Fields{"latency": elapsed.Milliseconds()}))
98
                } else {
99
                        g.logger().Info(ctx, slowLog, g.fields(log.Fields{"rows": rows, "latency": elapsed.Milliseconds()}))
100
                }
101
        case g.logLevel == logger.Info:
102
                sql, rows := fc()
103
                sql = g.format(sql)
104
                if rows == -1 {
105
                        g.logger().Info(ctx, sql, g.fields(log.Fields{"latency": elapsed.Milliseconds()}))
106
                } else {
107
                        g.logger().Info(ctx, sql, g.fields(log.Fields{"rows": rows, "latency": elapsed.Milliseconds()}))
108
                }
109
        }
110
}
func gormLogger.getLogLevel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

135
func (g *gormLogger) getLogLevel(level string) logger.LogLevel {
136
        switch strings.ToLower(level) {
137
        case "debug":
138
                return logger.Info
139
        case "info":
140
                return logger.Info
141
        case "warn":
142
                return logger.Warn
143
        case "error":
144
                return logger.Error
145
        default:
146
                return g.logLevel
147
        }
148
}
func httpLogger.Debugf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

48
func (h *httpLogger) Debugf(format string, v ...any) {
49
        if h.reloadConfig(); h.enabled {
50
                ctx, args := h.parseArgs(v...)
51
                h.logger().Debug(ctx, format, args...)
52
        }
53
}
func httpLogger.Errorf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

36
func (h *httpLogger) Errorf(format string, v ...any) {
37
        if h.reloadConfig(); h.enabled {
38
                ctx, args := h.parseArgs(v...)
39
                h.logger().Error(ctx, format, args...)
40
        }
41
}
func @64:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/redis.go:

64
func(ctx context.Context, cmds []rdsDrv.Cmder) (err error) {
65
                if !r.isLoggable() {
66
                        return next(ctx, cmds)
67
                }
68
                begin := time.Now()
69
                fullNameSb := new(strings.Builder)
70
                for _, cmd := range cmds {
71
                        _, _ = fullNameSb.WriteString(cmd.FullName() + " -> ")
72
                }
73
74
                if err = next(ctx, cmds); err != nil {
75
                        r.logger().Warn(ctx, "%s failed", fullNameSb.String(),
76
                                r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
77
                        return
78
                }
79
80
                r.logger().Info(ctx, "%s succeeded", fullNameSb.String(),
81
                        r.fields(log.Fields{"latency": time.Since(begin).Milliseconds()}))
82
                return
83
        }
func httpLogger.parseArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

62
func (h *httpLogger) parseArgs(args ...any) (ctx context.Context, params []any) {
63
        var ok bool
64
65
        if len(args) == 0 {
66
                return context.Background(), []any{httpFields}
67
        }
68
        if len(args) == 1 {
69
                args = append(args, httpFields)
70
                return context.Background(), args
71
        }
72
73
        params = args
74
        ctx, ok = args[0].(context.Context)
75
        if ok {
76
                params = args[1:]
77
        }
78
79
        if ctx == nil {
80
                ctx = context.Background()
81
        }
82
83
        params = append(params, httpFields)
84
        return
85
}
func routineLogger.parseArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

52
func (r *routineLogger) parseArgs(args ...any) (ctx context.Context, params []any) {
53
        var ok bool
54
55
        if len(args) == 0 {
56
                return context.Background(), []any{routineFields}
57
        }
58
        if len(args) == 1 {
59
                args = append(args, routineFields)
60
                return context.Background(), args
61
        }
62
63
        params = args
64
        ctx, ok = args[0].(context.Context)
65
        if ok {
66
                params = args[1:]
67
        }
68
69
        if ctx == nil {
70
                ctx = context.Background()
71
        }
72
73
        params = append(params, routineFields)
74
        return
75
}
func mqLogger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

44
func (m *mqLogger) Error(msg string, err error, fields watermill.LogFields) {
45
        if !m.isLoggable() {
46
                return
47
        }
48
        ctx, fs := m.parseLogFields(fields)
49
        if err != nil {
50
                m.logger().Error(ctx, msg+": %s", err, fs)
51
        } else {
52
                m.logger().Error(ctx, msg, err, fs)
53
        }
54
}
func asyncLogger.Debug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

51
func (a *asyncLogger) Debug(args ...any) {
52
        if !a.isLoggable() {
53
                return
54
        }
55
        ctx, format, args := a.parseArgs(args...)
56
        a.logger().Debug(ctx, format, args...)
57
}
func asyncLogger.Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

69
func (a *asyncLogger) Warn(args ...any) {
70
        if !a.isLoggable() {
71
                return
72
        }
73
        ctx, format, args := a.parseArgs(args...)
74
        a.logger().Warn(ctx, format, args...)
75
}
func cronLogger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

78
func (c *cronLogger) Error(args ...any) {
79
        if !c.isLoggable() {
80
                return
81
        }
82
        ctx, format, args := c.parseArgs(args...)
83
        c.logger().Error(ctx, format, args...)
84
}
func asyncLogger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

78
func (a *asyncLogger) Error(args ...any) {
79
        if !a.isLoggable() {
80
                return
81
        }
82
        ctx, format, args := a.parseArgs(args...)
83
        a.logger().Error(ctx, format, args...)
84
}
func metricsLogger.Fatal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

84
func (m *metricsLogger) Fatal(args ...any) {
85
        if !m.isLoggable() {
86
                return
87
        }
88
        ctx, format, args := m.parseArgs(args...)
89
        m.logger().Fatal(ctx, format, args...)
90
}
func cronLogger.Fatal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

88
func (c *cronLogger) Fatal(args ...any) {
89
        if !c.isLoggable() {
90
                return
91
        }
92
        ctx, format, args := c.parseArgs(args...)
93
        c.logger().Fatal(ctx, format, args...)
94
}
func asyncLogger.Fatal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

88
func (a *asyncLogger) Fatal(args ...any) {
89
        if !a.isLoggable() {
90
                return
91
        }
92
        ctx, format, args := a.parseArgs(args...)
93
        a.logger().Fatal(ctx, format, args...)
94
}
func metricsLogger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

74
func (m *metricsLogger) Error(args ...any) {
75
        if !m.isLoggable() {
76
                return
77
        }
78
        ctx, format, args := m.parseArgs(args...)
79
        m.logger().Error(ctx, format, args...)
80
}
func httpLogger.Warnf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

42
func (h *httpLogger) Warnf(format string, v ...any) {
43
        if h.reloadConfig(); h.enabled {
44
                ctx, args := h.parseArgs(v...)
45
                h.logger().Info(ctx, format, args...)
46
        }
47
}
func metricsLogger.Printf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

39
func (m *metricsLogger) Printf(format string, args ...any) {
40
        if !m.isLoggable() {
41
                return
42
        }
43
        m.logger().Info(context.Background(), format, append(args, metricsFields)...)
44
}
func DefaultMongoLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mongo.go:

41
func DefaultMongoLogger() (logger *mongoLogger) {
42
        logger = &mongoLogger{
43
                enabled:    true,
44
                requestMap: make(map[int64]struct{ commandString string }),
45
                loggableCommandSet: utils.NewSet[string](
46
                        "ping",
47
                        "insert",
48
                        "find",
49
                        "update",
50
                        "delete",
51
                        "aggregate",
52
                        "distinct",
53
                        "count",
54
                        "findAndModify",
55
                        "getMore",
56
                        "killCursors",
57
                        "create",
58
                        "drop",
59
                        "listDatabases",
60
                        "dropDatabase",
61
                        "createIndexes",
62
                        "listIndexes",
63
                        "dropIndexes",
64
                        "listCollections",
65
                ),
66
        }
67
        logger.CommandMonitor = &event.CommandMonitor{
68
                Started:   logger.started,
69
                Succeeded: logger.succeeded,
70
                Failed:    logger.failed,
71
        }
72
        return
73
}
func httpLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

55
func (h *httpLogger) logger() log.Loggable {
56
        if h.log != nil {
57
                return h.log
58
        }
59
        return log.Use(config.DefaultInstanceKey, log.AppName(h.appName))
60
}
func routineLogger.Printf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

38
func (r *routineLogger) Printf(format string, args ...any) {
39
        if r.reloadConfig(); r.enabled {
40
                ctx, args := r.parseArgs(args...)
41
                r.logger().Info(ctx, format, args...)
42
        }
43
}
func asyncLogger.Printf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

43
func (a *asyncLogger) Printf(format string, args ...any) {
44
        if !a.isLoggable() {
45
                return
46
        }
47
        a.logger().Info(context.Background(), format, append(args, asyncFields)...)
48
}
func routineLogger.logger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

45
func (r *routineLogger) logger() log.Loggable {
46
        if r.log != nil {
47
                return r.log
48
        }
49
        return log.Use(config.DefaultInstanceKey, log.AppName(r.appName))
50
}
func gormLogger.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

66
func (g *gormLogger) Error(ctx context.Context, msg string, data ...any) {
67
        if g.isLoggable() && g.logLevel >= logger.Error {
68
                g.logger().Error(ctx, msg, append(data, dbFields)...)
69
        }
70
}
func gormLogger.LogMode
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

46
func (g *gormLogger) LogMode(level logger.LogLevel) logger.Interface {
47
        g.logLevel = level
48
        return g
49
}
func gormLogger.Warn
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

59
func (g *gormLogger) Warn(ctx context.Context, msg string, data ...any) {
60
        if g.isLoggable() && g.logLevel >= logger.Warn {
61
                g.logger().Warn(ctx, msg, append(data, dbFields)...)
62
        }
63
}
func DefaultHttpLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/http.go:

20
func DefaultHttpLogger() resty.Logger {
21
        return new(httpLogger)
22
}
func DefaultRoutineLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/routine.go:

20
func DefaultRoutineLogger() ants.Logger {
21
        return &routineLogger{
22
                enabled: true,
23
        }
24
}
func DefaultAsyncLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

21
func DefaultAsyncLogger() interface{ Printf(string, ...any) } {
22
        return &asyncLogger{}
23
}
func DefaultAsynqAsyncLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/async.go:

25
func DefaultAsynqAsyncLogger() asynq.Logger {
26
        return &asyncLogger{}
27
}
func DefaultMySQLLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/gorm.go:

26
func DefaultMySQLLogger() logger.Interface {
27
        return &gormLogger{
28
                enabled:                   true,
29
                slowThreshold:             200 * time.Millisecond,
30
                logLevel:                  logger.Silent,
31
                ignoreRecordNotFoundError: true,
32
        }
33
}
func NewLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/mq.go:

32
func NewLogger() watermill.LoggerAdapter {
33
        return new(mqLogger)
34
}
func DefaultAsynqCronLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/cron.go:

25
func DefaultAsynqCronLogger() asynq.Logger {
26
        return &cronLogger{}
27
}
func DefaultMetricsLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/customlogger/metrics.go:

21
func DefaultMetricsLogger() metrics.Logger {
22
        return &metricsLogger{}
23
}
Package Overview: github.com/wfusion/gofusion/log/encoder 100.0%

Please select a function to see what's left for testing.

@58:9(...) github.com/wfusion/gofusion/log/encoder/skip_caller.go 100.0% 8/8
init(...) github.com/wfusion/gofusion/log/encoder/skip_caller.go 100.0% 2/2
SkipCallerEncoder(...) github.com/wfusion/gofusion/log/encoder/skip_caller.go 100.0% 2/2
func @58:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/encoder/skip_caller.go:

58
func(entryCaller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
59
                caller := utils.GetCaller(
60
                        maximumCallerDepth,
61
                        skipGlobOpt,
62
                        defaultSuffixedRegOpt,
63
                        minimumCallerDepthOpt,
64
                )
65
66
                entryCaller.PC = caller.PC
67
                entryCaller.File = caller.File
68
                entryCaller.Line = caller.Line
69
                entryCaller.Function = caller.Function
70
                if shorter {
71
                        enc.AppendString(entryCaller.TrimmedPath())
72
                } else {
73
                        enc.AppendString(entryCaller.FullPath())
74
                }
75
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/encoder/skip_caller.go:

49
func init() {
50
        defaultSuffixedRegOpt = utils.SkipRegexps(defaultSuffixesRegPatternList...)
51
        minimumCallerDepthOpt = utils.SkipKnownDepth(knownLogrusFrames)
52
}
func SkipCallerEncoder
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/log/encoder/skip_caller.go:

55
func SkipCallerEncoder(skipSuffixed []string, shorter bool) func(
56
        caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
57
        skipGlobOpt := utils.SkipGlobs(skipSuffixed...)
58
        return func(entryCaller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
59
                caller := utils.GetCaller(
60
                        maximumCallerDepth,
61
                        skipGlobOpt,
62
                        defaultSuffixedRegOpt,
63
                        minimumCallerDepthOpt,
64
                )
65
66
                entryCaller.PC = caller.PC
67
                entryCaller.File = caller.File
68
                entryCaller.Line = caller.Line
69
                entryCaller.Function = caller.Function
70
                if shorter {
71
                        enc.AppendString(entryCaller.TrimmedPath())
72
                } else {
73
                        enc.AppendString(entryCaller.FullPath())
74
                }
75
        }
76
}
Package Overview: github.com/wfusion/gofusion/metrics 72.5%

Please select a function to see what's left for testing.

@32:9(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 13/13
Internal(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 11/11
abstract.convertOpts(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 9/9
Construct(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 7/7
@243:5(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 2/2
newMock(...) github.com/wfusion/gofusion/metrics/mock.go 100.0% 2/2
@285:57(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
Labels(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
@126:9(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
@108:9(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 1/1
@120:9(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
WithoutTimeout(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/metrics/construct.go 100.0% 1/1
abstract.SetGauge(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
abstract.IncrCounter(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
abstract.AddSample(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
abstract.MeasureSince(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
abstract.IsEnableServiceLabel(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
@336:33(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
abstract.convertLabels(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
@114:9(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
abstract.start(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
PrometheusBuckets(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
Timeout(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
@108:9(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
@262:36(...) github.com/wfusion/gofusion/metrics/metrics.go 100.0% 1/1
Precision(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
@102:9(...) github.com/wfusion/gofusion/metrics/types.go 100.0% 1/1
newMetrics(...) github.com/wfusion/gofusion/metrics/metrics.go 96.0% 24/25
addConfig(...) github.com/wfusion/gofusion/metrics/construct.go 90.9% 20/22
use(...) github.com/wfusion/gofusion/metrics/construct.go 87.0% 20/23
abstract.setGaugeWithLabels(...) github.com/wfusion/gofusion/metrics/metrics.go 85.7% 6/7
abstract.addSampleWithLabels(...) github.com/wfusion/gofusion/metrics/metrics.go 85.7% 6/7
@279:23(...) github.com/wfusion/gofusion/metrics/metrics.go 85.7% 6/7
Use(...) github.com/wfusion/gofusion/metrics/construct.go 80.0% 8/10
abstract.shutdown(...) github.com/wfusion/gofusion/metrics/metrics.go 75.0% 3/4
abstract.measureSinceWithLabels(...) github.com/wfusion/gofusion/metrics/metrics.go 75.0% 3/4
@245:19(...) github.com/wfusion/gofusion/metrics/metrics.go 75.0% 3/4
newPrometheusPush(...) github.com/wfusion/gofusion/metrics/prometheus.go 75.0% 3/4
abstract.process(...) github.com/wfusion/gofusion/metrics/metrics.go 75.0% 3/4
abstract.incrCounterWithLabels(...) github.com/wfusion/gofusion/metrics/metrics.go 75.0% 3/4
@246:25(...) github.com/wfusion/gofusion/metrics/metrics.go 70.0% 7/10
abstract.send(...) github.com/wfusion/gofusion/metrics/metrics.go 24.2% 8/33
HttpHandler(...) github.com/wfusion/gofusion/metrics/http.go 0.0% 0/12
newPrometheusPull(...) github.com/wfusion/gofusion/metrics/prometheus.go 0.0% 0/8
task.String(...) github.com/wfusion/gofusion/metrics/metrics.go 0.0% 0/4
abstract.getProxy(...) github.com/wfusion/gofusion/metrics/metrics.go 0.0% 0/1
@114:9(...) github.com/wfusion/gofusion/metrics/construct.go 0.0% 0/1
NewDI(...) github.com/wfusion/gofusion/metrics/construct.go 0.0% 0/1
func @32:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

32
func() {
33
                rwlock.Lock()
34
                defer rwlock.Unlock()
35
36
                pid := syscall.Getpid()
37
                app := config.Use(opt.AppName).AppName()
38
                if appInstances != nil {
39
                        for _, sinks := range appInstances[opt.AppName] {
40
                                for name, sink := range sinks {
41
                                        log.Printf("%v [Gofusion] %s %s %s router exiting...",
42
                                                pid, app, config.ComponentMetrics, name)
43
                                        sink.shutdown()
44
                                        log.Printf("%v [Gofusion] %s %s %s router exited",
45
                                                pid, app, config.ComponentMetrics, name)
46
                                }
47
                        }
48
                        delete(appInstances, opt.AppName)
49
                }
50
51
                if cfgsMap != nil {
52
                        delete(cfgsMap, opt.AppName)
53
                }
54
        }
func Internal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

177
func Internal(opts ...utils.OptionExtender) (sinks []Sink) {
178
        opt := utils.ApplyOptions[useOption](opts...)
179
        appName := config.Use(opt.appName).AppName()
180
        rwlock.Lock()
181
        defer rwlock.Unlock()
182
        cfgs, ok := cfgsMap[opt.appName]
183
        if !ok {
184
                return
185
        }
186
        for _, cfg := range cfgs {
187
                if cfg.c.EnableInternalMetrics {
188
                        sinks = append(sinks, use(appName, cfg))
189
                }
190
        }
191
        return
192
}
func abstract.convertOpts
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

343
func (a *abstract) convertOpts(src ...utils.OptionExtender) (dst []utils.OptionExtender) {
344
        if src == nil {
345
                return
346
        }
347
348
        dst = make([]utils.OptionExtender, 0, len(src))
349
        opt := utils.ApplyOptions[option](src...)
350
        if opt.precision {
351
                dst = append(dst, metrics.Precision())
352
        }
353
        if len(opt.prometheusBuckets) > 0 {
354
                dst = append(dst, prometheus.Bucket(opt.prometheusBuckets))
355
        }
356
357
        return
358
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

22
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
23
        opt := utils.ApplyOptions[config.InitOption](opts...)
24
        optU := utils.ApplyOptions[useOption](opts...)
25
        if opt.AppName == "" {
26
                opt.AppName = optU.appName
27
        }
28
        for name, conf := range confs {
29
                addConfig(ctx, name, conf, opt)
30
        }
31
32
        return func() {
33
                rwlock.Lock()
34
                defer rwlock.Unlock()
35
36
                pid := syscall.Getpid()
37
                app := config.Use(opt.AppName).AppName()
38
                if appInstances != nil {
39
                        for _, sinks := range appInstances[opt.AppName] {
40
                                for name, sink := range sinks {
41
                                        log.Printf("%v [Gofusion] %s %s %s router exiting...",
42
                                                pid, app, config.ComponentMetrics, name)
43
                                        sink.shutdown()
44
                                        log.Printf("%v [Gofusion] %s %s %s router exited",
45
                                                pid, app, config.ComponentMetrics, name)
46
                                }
47
                        }
48
                        delete(appInstances, opt.AppName)
49
                }
50
51
                if cfgsMap != nil {
52
                        delete(cfgsMap, opt.AppName)
53
                }
54
        }
55
}
func @243:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

243
func() {
244
                appName := config.Use(a.appName).AppName()
245
                _ = retry.Retry(func(attempt uint) (err error) {
246
                        _, err = utils.Catch(func() {
247
                                for {
248
                                        select {
249
                                        case <-a.ctx.Done():
250
                                                if a.log != nil {
251
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to context done",
252
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
253
                                                        return
254
                                                }
255
                                        case task, ok := <-a.queue:
256
                                                if !ok {
257
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to queue closed",
258
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
259
                                                        return
260
                                                }
261
262
                                                if err := a.queuePool.Submit(func() { _ = a.process(task) }); err != nil && a.log != nil {
263
                                                        a.log.Error(task.ctx, "%v [Gofusion] %s %s %s submit process %s error: %s",
264
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics,
265
                                                                a.name, task, err)
266
                                                }
267
                                        }
268
                                }
269
                        })
270
                        if err != nil {
271
                                a.log.Warn(a.ctx, "%v [Gofusion] %s %s %s dispatcher exited with error: %s",
272
                                        syscall.Getpid(), appName, config.ComponentMetrics, a.name, err)
273
                        }
274
                        return
275
                }, strategy.Limit(10000))
276
        }
func newMock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/mock.go:

13
func newMock(ctx context.Context, appName, name, job string, conf *cfg) Sink {
14
        sink := new(metrics.BlackholeSink)
15
        return &mock{abstract: newMetrics(ctx, appName, name, job, sink, conf)}
16
}
func @285:57
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

285
func(o utils.OptionExtender) any { return o }
func Labels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

125
func Labels(labels []Label) utils.OptionFunc[option] {
126
        return func(o *option) {
127
                o.labels = labels
128
        }
129
}
func @126:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

126
func(o *option) {
127
                o.labels = labels
128
        }
func @108:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

108
func(o *useOption) {
109
                o.appName = name
110
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

194
func init() {
195
        config.AddComponent(config.ComponentMetrics, Construct)
196
}
func @120:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

120
func(o *option) {
121
                o.timeout = -1
122
        }
func WithoutTimeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

119
func WithoutTimeout() utils.OptionFunc[option] {
120
        return func(o *option) {
121
                o.timeout = -1
122
        }
123
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

107
func AppName(name string) utils.OptionFunc[useOption] {
108
        return func(o *useOption) {
109
                o.appName = name
110
        }
111
}
func abstract.SetGauge
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

128
func (a *abstract) SetGauge(ctx context.Context, key []string, val float64, opts ...utils.OptionExtender) {
129
        a.send(ctx, "Gauge", key, val, opts...)
130
}
func abstract.IncrCounter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

131
func (a *abstract) IncrCounter(ctx context.Context, key []string, val float64, opts ...utils.OptionExtender) {
132
        a.send(ctx, "Counter", key, val, opts...)
133
}
func abstract.AddSample
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

134
func (a *abstract) AddSample(ctx context.Context, key []string, val float64, opts ...utils.OptionExtender) {
135
        a.send(ctx, "Sample", key, val, opts...)
136
}
func abstract.MeasureSince
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

137
func (a *abstract) MeasureSince(ctx context.Context, key []string, start time.Time, opts ...utils.OptionExtender) {
138
        a.send(ctx, "MeasureSince", key, start, opts...)
139
}
func abstract.IsEnableServiceLabel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

140
func (a *abstract) IsEnableServiceLabel() bool { return a.EnableServiceLabel }
func @336:33
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

336
func(l Label) metrics.Label {
337
                return metrics.Label{
338
                        Name:  l.Key,
339
                        Value: l.Value,
340
                }
341
        }
func abstract.convertLabels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

335
func (a *abstract) convertLabels(src []Label) (dst []metrics.Label) {
336
        return utils.SliceMapping(src, func(l Label) metrics.Label {
337
                return metrics.Label{
338
                        Name:  l.Key,
339
                        Value: l.Value,
340
                }
341
        })
342
}
func @114:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

114
func(o *option) {
115
                o.timeout = timeout
116
        }
func abstract.start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

242
func (a *abstract) start() {
243
        go func() {
244
                appName := config.Use(a.appName).AppName()
245
                _ = retry.Retry(func(attempt uint) (err error) {
246
                        _, err = utils.Catch(func() {
247
                                for {
248
                                        select {
249
                                        case <-a.ctx.Done():
250
                                                if a.log != nil {
251
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to context done",
252
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
253
                                                        return
254
                                                }
255
                                        case task, ok := <-a.queue:
256
                                                if !ok {
257
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to queue closed",
258
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
259
                                                        return
260
                                                }
261
262
                                                if err := a.queuePool.Submit(func() { _ = a.process(task) }); err != nil && a.log != nil {
263
                                                        a.log.Error(task.ctx, "%v [Gofusion] %s %s %s submit process %s error: %s",
264
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics,
265
                                                                a.name, task, err)
266
                                                }
267
                                        }
268
                                }
269
                        })
270
                        if err != nil {
271
                                a.log.Warn(a.ctx, "%v [Gofusion] %s %s %s dispatcher exited with error: %s",
272
                                        syscall.Getpid(), appName, config.ComponentMetrics, a.name, err)
273
                        }
274
                        return
275
                }, strategy.Limit(10000))
276
        }()
277
}
func PrometheusBuckets
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

101
func PrometheusBuckets(buckets []float64) utils.OptionFunc[option] {
102
        return func(o *option) {
103
                o.prometheusBuckets = buckets
104
        }
105
}
func Timeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

113
func Timeout(timeout time.Duration) utils.OptionFunc[option] {
114
        return func(o *option) {
115
                o.timeout = timeout
116
        }
117
}
func @108:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

108
func(o *option) {
109
                o.precision = true
110
        }
func @262:36
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

262
func() { _ = a.process(task) }
func Precision
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

107
func Precision() utils.OptionFunc[option] {
108
        return func(o *option) {
109
                o.precision = true
110
        }
111
}
func @102:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/types.go:

102
func(o *option) {
103
                o.prometheusBuckets = buckets
104
        }
func newMetrics
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

70
func newMetrics(ctx context.Context, appName, name, job string, sink metrics.MetricSink, conf *cfg) *abstract {
71
        metricsConfig := metrics.DefaultConfig(config.Use(appName).AppName())
72
        if conf.c.EnableServiceLabel {
73
                metricsConfig.EnableHostname = true
74
                metricsConfig.EnableHostnameLabel = true
75
                metricsConfig.EnableServiceLabel = true
76
                metricsConfig.EnableClientIPLabel = true
77
        } else {
78
                metricsConfig.EnableHostname = false
79
                metricsConfig.EnableHostnameLabel = false
80
                metricsConfig.EnableServiceLabel = false
81
                metricsConfig.EnableClientIPLabel = false
82
        }
83
84
        m, err := metrics.New(metricsConfig, sink)
85
        if err != nil {
86
                panic(errors.Errorf("initialize metrics failed: %s", err))
87
        }
88
89
        limit := defaultQueueLimit
90
        if conf.c.QueueLimit > 0 {
91
                limit = conf.c.QueueLimit
92
        }
93
        if conf.c.QueueConcurrency == 0 {
94
                conf.c.QueueConcurrency = runtime.NumCPU()
95
        }
96
97
        constLabels := make([]metrics.Label, 0, len(conf.c.Labels))
98
        for k, v := range conf.c.Labels {
99
                constLabels = append(constLabels, metrics.Label{Name: k, Value: v})
100
        }
101
102
        a := &abstract{
103
                Metrics: m,
104
105
                ctx:         ctx,
106
                constLabels: constLabels,
107
                job:         job,
108
                name:        name,
109
                appName:     appName,
110
                log:         conf.logger,
111
                stop:        make(chan struct{}),
112
                queue:       make(chan *task, limit),
113
                queuePool:   utils.Must(ants.NewPool(conf.c.QueueConcurrency)),
114
        }
115
116
        a.dispatcher = map[string]func(...any){
117
                "Gauge":        utils.WrapFunc(a.setGaugeWithLabels),
118
                "Counter":      utils.WrapFunc(a.incrCounterWithLabels),
119
                "Sample":       utils.WrapFunc(a.addSampleWithLabels),
120
                "MeasureSince": utils.WrapFunc(a.measureSinceWithLabels),
121
        }
122
123
        a.start()
124
125
        return a
126
}
func addConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

57
func addConfig(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
58
        var (
59
                err      error
60
                interval time.Duration
61
        )
62
        if utils.IsStrNotBlank(conf.Interval) {
63
                interval, err = time.ParseDuration(conf.Interval)
64
                if err != nil {
65
                        panic(errors.Errorf("metrics component parse %s interval failed: %s", name, err))
66
                }
67
        }
68
69
        rwlock.Lock()
70
        defer rwlock.Unlock()
71
        if cfgsMap == nil {
72
                cfgsMap = make(map[string]map[string]*cfg)
73
        }
74
        if cfgsMap[opt.AppName] == nil {
75
                cfgsMap[opt.AppName] = make(map[string]*cfg)
76
        }
77
        if _, ok := cfgsMap[opt.AppName][name]; ok {
78
                panic(ErrDuplicatedName)
79
        }
80
81
        var logger metrics.Logger
82
        if utils.IsStrNotBlank(conf.Logger) {
83
                loggerType := inspect.TypeOf(conf.Logger)
84
                loggerValue := reflect.New(loggerType)
85
                if loggerValue.Type().Implements(customLoggerType) {
86
                        logger := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
87
                        loggerValue.Interface().(customLogger).Init(logger, opt.AppName, name)
88
                }
89
                logger = loggerValue.Convert(metricsLoggerType).Interface().(metrics.Logger)
90
        }
91
92
        cfgsMap[opt.AppName][name] = &cfg{
93
                c:          conf,
94
                ctx:        ctx,
95
                name:       name,
96
                appName:    opt.AppName,
97
                interval:   interval,
98
                initOption: opt,
99
                logger:     logger,
100
        }
101
}
func use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

135
func use(job string, conf *cfg) (sink Sink) {
136
        if appInstances == nil {
137
                appInstances = make(map[string]map[string]map[string]Sink)
138
        }
139
        instances, ok := appInstances[conf.appName]
140
        if !ok {
141
                instances = make(map[string]map[string]Sink)
142
                appInstances[conf.appName] = instances
143
        }
144
145
        jobs, ok := instances[conf.name]
146
        if !ok {
147
                jobs = make(map[string]Sink)
148
                instances[conf.name] = jobs
149
        }
150
        sink, ok = jobs[job]
151
        if ok {
152
                return
153
        }
154
155
        switch conf.c.Type {
156
        case metricsTypePrometheus:
157
                switch conf.c.Mode {
158
                case modePull:
159
                        sink = newPrometheusPull(conf.ctx, conf.appName, conf.name, job, conf)
160
                case modePush:
161
                        sink = newPrometheusPush(conf.ctx, conf.appName, conf.name, job, conf.interval, conf)
162
                }
163
        case metricsTypeMock:
164
                sink = newMock(conf.ctx, conf.appName, conf.name, job, conf)
165
        default:
166
                panic(errors.Errorf("unknown metrics type: %s", conf.c.Type))
167
        }
168
169
        if sink == nil {
170
                panic(errors.Errorf("unknown metrics mode: %s", conf.c.Mode))
171
        }
172
173
        jobs[job] = sink
174
        return
175
}
func abstract.setGaugeWithLabels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

296
func (a *abstract) setGaugeWithLabels(key []string, v any, labels []metrics.Label, opts ...utils.OptionExtender) {
297
        val, ok := v.(float64)
298
        if !ok {
299
                return
300
        }
301
        opt := utils.ApplyOptions[option](opts...)
302
        if opt.precision {
303
                a.Metrics.SetPrecisionGaugeWithLabels(key, val, labels, opts...)
304
        } else {
305
                a.Metrics.SetGaugeWithLabels(key, float32(val), labels, opts...)
306
        }
307
}
func abstract.addSampleWithLabels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

315
func (a *abstract) addSampleWithLabels(key []string, v any, labels []metrics.Label, opts ...utils.OptionExtender) {
316
        val, ok := v.(float64)
317
        if !ok {
318
                return
319
        }
320
        opt := utils.ApplyOptions[option](opts...)
321
        if opt.precision {
322
                a.Metrics.AddPrecisionSampleWithLabels(key, val, labels, opts...)
323
        } else {
324
                a.Metrics.AddSampleWithLabels(key, float32(val), labels, opts...)
325
        }
326
}
func @279:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

279
func() (err error) {
280
                handler, ok := a.dispatcher[task.method]
281
                if !ok {
282
                        return errors.Errorf("method %s not found", task.method)
283
                }
284
                params := []any{task.key, task.val, append(task.labels, a.constLabels...)}
285
                params = append(params, utils.SliceMapping(task.opts, func(o utils.OptionExtender) any { return o })...)
286
                handler(params...)
287
                return
288
        }
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

119
func Use(name, job string, opts ...utils.OptionExtender) Sink {
120
        opt := utils.ApplyOptions[useOption](opts...)
121
        rwlock.Lock()
122
        defer rwlock.Unlock()
123
        cfgs, ok := cfgsMap[opt.appName]
124
        if !ok {
125
                panic(errors.Errorf("app metrics config not found: %s", opt.appName))
126
        }
127
        cfg, ok := cfgs[name]
128
        if !ok {
129
                panic(errors.Errorf("metrics config not found: %s", name))
130
        }
131
132
        return use(job, cfg)
133
}
func abstract.shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

145
func (a *abstract) shutdown() {
146
        if _, ok := utils.IsChannelClosed(a.stop); ok {
147
                return
148
        }
149
150
        close(a.stop)
151
        a.Metrics.Shutdown()
152
}
func abstract.measureSinceWithLabels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

327
func (a *abstract) measureSinceWithLabels(key []string, v any, labels []metrics.Label, opts ...utils.OptionExtender) {
328
        start, ok := v.(time.Time)
329
        if !ok {
330
                return
331
        }
332
        a.Metrics.MeasureSinceWithLabels(key, start, labels, opts...)
333
}
func @245:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

245
func(attempt uint) (err error) {
246
                        _, err = utils.Catch(func() {
247
                                for {
248
                                        select {
249
                                        case <-a.ctx.Done():
250
                                                if a.log != nil {
251
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to context done",
252
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
253
                                                        return
254
                                                }
255
                                        case task, ok := <-a.queue:
256
                                                if !ok {
257
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to queue closed",
258
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
259
                                                        return
260
                                                }
261
262
                                                if err := a.queuePool.Submit(func() { _ = a.process(task) }); err != nil && a.log != nil {
263
                                                        a.log.Error(task.ctx, "%v [Gofusion] %s %s %s submit process %s error: %s",
264
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics,
265
                                                                a.name, task, err)
266
                                                }
267
                                        }
268
                                }
269
                        })
270
                        if err != nil {
271
                                a.log.Warn(a.ctx, "%v [Gofusion] %s %s %s dispatcher exited with error: %s",
272
                                        syscall.Getpid(), appName, config.ComponentMetrics, a.name, err)
273
                        }
274
                        return
275
                }
func newPrometheusPush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/prometheus.go:

24
func newPrometheusPush(ctx context.Context, appName, name, job string, interval time.Duration, conf *cfg) Sink {
25
        sink, err := prometheus.NewPrometheusPushSink(ctx, conf.c.Endpoint.Addresses[0], interval, job, conf.logger)
26
        if err != nil {
27
                panic(errors.Errorf("initialize metrics component push mode prometheus failed: %s", err))
28
        }
29
        return &_Prometheus{abstract: newMetrics(ctx, appName, name, job, sink, conf)}
30
}
func abstract.process
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

278
func (a *abstract) process(task *task) (err error) {
279
        _, err = utils.Catch(func() (err error) {
280
                handler, ok := a.dispatcher[task.method]
281
                if !ok {
282
                        return errors.Errorf("method %s not found", task.method)
283
                }
284
                params := []any{task.key, task.val, append(task.labels, a.constLabels...)}
285
                params = append(params, utils.SliceMapping(task.opts, func(o utils.OptionExtender) any { return o })...)
286
                handler(params...)
287
                return
288
        })
289
        if err != nil && a.log != nil {
290
                a.log.Error(task.ctx, "%v [Gofusion] %s %s %s process %s catch error: %s",
291
                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name, task, err)
292
        }
293
        return
294
}
func abstract.incrCounterWithLabels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

308
func (a *abstract) incrCounterWithLabels(key []string, v any, labels []metrics.Label, opts ...utils.OptionExtender) {
309
        val, ok := v.(float64)
310
        if !ok {
311
                return
312
        }
313
        a.Metrics.IncrCounterWithLabels(key, float32(val), labels, opts...)
314
}
func @246:25
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

246
func() {
247
                                for {
248
                                        select {
249
                                        case <-a.ctx.Done():
250
                                                if a.log != nil {
251
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to context done",
252
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
253
                                                        return
254
                                                }
255
                                        case task, ok := <-a.queue:
256
                                                if !ok {
257
                                                        a.log.Info(a.ctx, "%v [Gofusion] %s %s %s process exited due to queue closed",
258
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
259
                                                        return
260
                                                }
261
262
                                                if err := a.queuePool.Submit(func() { _ = a.process(task) }); err != nil && a.log != nil {
263
                                                        a.log.Error(task.ctx, "%v [Gofusion] %s %s %s submit process %s error: %s",
264
                                                                syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics,
265
                                                                a.name, task, err)
266
                                                }
267
                                        }
268
                                }
269
                        }
func abstract.send
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

154
func (a *abstract) send(ctx context.Context, method string, key []string, val any, opts ...utils.OptionExtender) {
155
        opt := utils.ApplyOptions[option](opts...)
156
157
        t := &task{
158
                ctx:    ctx,
159
                key:    key,
160
                val:    val,
161
                opts:   append(opts, a.convertOpts(opts...)...),
162
                labels: a.convertLabels(opt.labels),
163
                method: method,
164
        }
165
166
        switch {
167
        case opt.timeout > 0:
168
                timeoutCtx, cancel := context.WithTimeout(a.ctx, opt.timeout)
169
                defer cancel()
170
171
                select {
172
                case a.queue <- t:
173
                case <-ctx.Done():
174
                        if a.log != nil {
175
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to context done",
176
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
177
                        }
178
                case <-timeoutCtx.Done():
179
                        if a.log != nil {
180
                                a.log.Warn(ctx, "%v [Gofusion] %s %s %s async send task canceled due to timeout %s",
181
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name, opt.timeout)
182
                        }
183
                case <-a.stop:
184
                        close(a.queue)
185
                        if a.log != nil {
186
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to metrics stopped",
187
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
188
                        }
189
                case <-a.ctx.Done():
190
                        if a.log != nil {
191
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to app exited",
192
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
193
                        }
194
                }
195
        case opt.timeout < 0:
196
                select {
197
                case a.queue <- t:
198
                case <-ctx.Done():
199
                        if a.log != nil {
200
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to context done",
201
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
202
                        }
203
                case <-a.stop:
204
                        close(a.queue)
205
                        if a.log != nil {
206
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to metrics stopped",
207
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
208
                        }
209
                case <-a.ctx.Done():
210
                        if a.log != nil {
211
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to app exited",
212
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
213
                        }
214
                }
215
        default:
216
                select {
217
                case a.queue <- t:
218
                case <-ctx.Done():
219
                        if a.log != nil {
220
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to context done",
221
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
222
                        }
223
                case <-a.ctx.Done():
224
                        if a.log != nil {
225
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to app exited",
226
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
227
                        }
228
                case <-a.stop:
229
                        close(a.queue)
230
                        if a.log != nil {
231
                                a.log.Info(ctx, "%v [Gofusion] %s %s %s async send task canceled due to metrics stopped",
232
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
233
                        }
234
                default:
235
                        if a.log != nil {
236
                                a.log.Warn(ctx, "%v [Gofusion] %s %s %s async send task canceled due to exceed the queue limit",
237
                                        syscall.Getpid(), config.Use(a.appName).AppName(), config.ComponentMetrics, a.name)
238
                        }
239
                }
240
        }
241
}
func HttpHandler
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/http.go:

15
func HttpHandler(path, name string, opts ...utils.OptionExtender) http.Handler {
16
        opt := utils.ApplyOptions[useOption](opts...)
17
        rwlock.RLock()
18
        defer rwlock.RUnlock()
19
20
        if appInstances == nil || appInstances[opt.appName] == nil || appInstances[opt.appName][name] == nil {
21
                panic(errors.Errorf("metrics instance not found: %s %s", opt.appName, name))
22
        }
23
24
        // cfg := cfgsMap[opt.appName][name]
25
        m := utils.MapValues(appInstances[opt.appName][name])[0]
26
        switch sink := m.getProxy().(type) {
27
        case *prometheus.PrometheusSink:
28
                gatherer, ok := sink.Registry.(proDrv.Gatherer)
29
                if !ok {
30
                        gatherer = proDrv.DefaultGatherer
31
                }
32
                return promhttp.InstrumentMetricHandler(
33
                        sink.Registry, promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}),
34
                )
35
        default:
36
                panic(errors.Errorf("metrics instance not support http exporter: %s %s", opt.appName, name))
37
        }
38
}
func newPrometheusPull
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/prometheus.go:

32
func newPrometheusPull(ctx context.Context, appName, name, job string, conf *cfg) Sink {
33
        prometheusRWLocker.Lock()
34
        if _, ok := prometheusRegisters[appName]; !ok {
35
                prometheusRegisters[appName] = proDrv.NewRegistry()
36
        }
37
        prometheusRWLocker.Unlock()
38
39
        sink, err := prometheus.NewPrometheusSinkFrom(prometheus.PrometheusOpts{
40
                Expiration:           prometheus.DefaultPrometheusOpts.Expiration,
41
                Registerer:           prometheusRegisters[appName],
42
                GaugeDefinitions:     nil,
43
                SummaryDefinitions:   nil,
44
                CounterDefinitions:   nil,
45
                HistogramDefinitions: nil,
46
                Name:                 job,
47
        })
48
        if err != nil {
49
                panic(errors.Errorf("initialize metrics component pull mode prometheus failed: %s", err))
50
        }
51
52
        return &_Prometheus{abstract: newMetrics(ctx, appName, name, job, sink, conf)}
53
}
func task.String
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

61
func (t *task) String() string {
62
        label := make(map[string]string, len(t.labels))
63
        for _, l := range t.labels {
64
                label[l.Name] = l.Value
65
        }
66
67
        return fmt.Sprintf("%s:%s:%+v(%+v)", t.method, strings.Join(t.key, constant.Dot), t.val, label)
68
}
func abstract.getProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/metrics.go:

142
func (a *abstract) getProxy() any {
143
        return inspect.GetField[metrics.MetricSink](a.Metrics, "sink")
144
}
func @114:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

114
func() Sink {
115
                return Use(name, job, opts...)
116
        }
func NewDI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/metrics/construct.go:

113
func NewDI(name, job string, opts ...utils.OptionExtender) func() Sink {
114
        return func() Sink {
115
                return Use(name, job, opts...)
116
        }
117
}
Package Overview: github.com/wfusion/gofusion/mongo 76.6%

Please select a function to see what's left for testing.

metricsPoolMonitor(...) github.com/wfusion/gofusion/mongo/metrics.go 100.0% 13/13
startDaemonRoutines(...) github.com/wfusion/gofusion/mongo/metrics.go 100.0% 10/10
Construct(...) github.com/wfusion/gofusion/mongo/construct.go 100.0% 7/7
@160:9(...) github.com/wfusion/gofusion/mongo/metrics.go 100.0% 5/5
@59:25(...) github.com/wfusion/gofusion/mongo/metrics.go 100.0% 4/4
@83:9(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/mongo/construct.go 100.0% 1/1
metricMongoStats(...) github.com/wfusion/gofusion/mongo/metrics.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
WriteConcern(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
@72:9(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
instance.GetProxy(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
instance.Database(...) github.com/wfusion/gofusion/mongo/mongo.go 100.0% 1/1
addInstance(...) github.com/wfusion/gofusion/mongo/construct.go 91.3% 21/23
@33:9(...) github.com/wfusion/gofusion/mongo/construct.go 88.9% 8/9
Use(...) github.com/wfusion/gofusion/mongo/mongo.go 81.8% 9/11
metricMongoLatency(...) github.com/wfusion/gofusion/mongo/metrics.go 66.7% 2/3
@101:21(...) github.com/wfusion/gofusion/mongo/metrics.go 60.0% 12/20
@57:21(...) github.com/wfusion/gofusion/mongo/metrics.go 47.4% 9/19
@87:4(...) github.com/wfusion/gofusion/mongo/construct.go 0.0% 0/1
ReadConcern(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
@78:9(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
@88:9(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
BsonOptions(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
@93:9(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
Registry(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
@98:9(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
ReadPreference(...) github.com/wfusion/gofusion/mongo/mongo.go 0.0% 0/1
func metricsPoolMonitor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

142
func metricsPoolMonitor(appName, name string) func(evt *event.PoolEvent) {
143
        metricsPoolLocker.Lock()
144
        defer metricsPoolLocker.Unlock()
145
        if metricsPoolTotalCounter[appName] == nil {
146
                metricsPoolTotalCounter[appName] = make(map[string]*atomic.Int64)
147
        }
148
        if metricsPoolTotalCounter[appName][name] == nil {
149
                metricsPoolTotalCounter[appName][name] = atomic.NewInt64(0)
150
        }
151
        if metricsPoolInUseCounter[appName] == nil {
152
                metricsPoolInUseCounter[appName] = make(map[string]*atomic.Int64)
153
        }
154
        if metricsPoolInUseCounter[appName][name] == nil {
155
                metricsPoolInUseCounter[appName][name] = atomic.NewInt64(0)
156
        }
157
158
        inuse := metricsPoolInUseCounter[appName][name]
159
        total := metricsPoolTotalCounter[appName][name]
160
        return func(evt *event.PoolEvent) {
161
                switch evt.Type {
162
                case event.PoolCreated:
163
                case event.PoolReady:
164
                case event.PoolCleared:
165
                case event.PoolClosedEvent:
166
                case event.ConnectionCreated:
167
                        total.Add(1)
168
                case event.ConnectionReady:
169
                case event.ConnectionClosed:
170
                        total.Add(-1)
171
                case event.GetStarted:
172
                case event.GetFailed:
173
                case event.GetSucceeded:
174
                        inuse.Add(1)
175
                case event.ConnectionReturned:
176
                        inuse.Add(-1)
177
                }
178
        }
179
180
}
func startDaemonRoutines
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

34
func startDaemonRoutines(ctx context.Context, appName, name string, conf *Conf) {
35
        ticker := time.Tick(time.Second * 5)
36
        app := config.Use(appName).AppName()
37
        labels := []metrics.Label{
38
                {Key: "config", Value: name},
39
                {Key: "database", Value: conf.DB},
40
        }
41
42
        log.Printf("%v [Gofusion] %s %s %s metrics start", syscall.Getpid(), app, config.ComponentMongo, name)
43
        for {
44
                select {
45
                case <-ctx.Done():
46
                        log.Printf("%v [Gofusion] %s %s %s metrics exited",
47
                                syscall.Getpid(), app, config.ComponentMongo, name)
48
                        return
49
                case <-ticker:
50
                        go metricMongoStats(ctx, appName, name, labels)
51
                        go metricMongoLatency(ctx, appName, name, labels)
52
                }
53
        }
54
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/construct.go:

23
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
24
        opt := utils.ApplyOptions[config.InitOption](opts...)
25
        optU := utils.ApplyOptions[useOption](opts...)
26
        if opt.AppName == "" {
27
                opt.AppName = optU.appName
28
        }
29
        for name, conf := range confs {
30
                addInstance(ctx, name, conf, opt)
31
        }
32
33
        return func() {
34
                rwlock.Lock()
35
                defer rwlock.Unlock()
36
37
                pid := syscall.Getpid()
38
                app := config.Use(opt.AppName).AppName()
39
                if appInstances != nil {
40
                        for name, instance := range appInstances[opt.AppName] {
41
                                if err := instance.GetProxy().Disconnect(nil); err != nil {
42
                                        log.Printf("%v [Gofusion] %s %s %s disconnect error: %s",
43
                                                pid, app, config.ComponentMongo, name, err)
44
                                }
45
                        }
46
                        delete(appInstances, opt.AppName)
47
                }
48
        }
49
}
func @160:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

160
func(evt *event.PoolEvent) {
161
                switch evt.Type {
162
                case event.PoolCreated:
163
                case event.PoolReady:
164
                case event.PoolCleared:
165
                case event.PoolClosedEvent:
166
                case event.ConnectionCreated:
167
                        total.Add(1)
168
                case event.ConnectionReady:
169
                case event.ConnectionClosed:
170
                        total.Add(-1)
171
                case event.GetStarted:
172
                case event.GetFailed:
173
                case event.GetSucceeded:
174
                        inuse.Add(1)
175
                case event.ConnectionReturned:
176
                        inuse.Add(-1)
177
                }
178
        }
func @59:25
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

59
func() {
60
                        metricsPoolLocker.RLock()
61
                        defer metricsPoolLocker.RUnlock()
62
                        inuse = metricsPoolInUseCounter[appName][name].Load()
63
                        total = metricsPoolTotalCounter[appName][name].Load()
64
                }
func @83:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

83
func(o *useOption) {
84
                o.writeConcern = writeConcern
85
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/construct.go:

97
func init() {
98
        config.AddComponent(config.ComponentMongo, Construct)
99
}
func metricMongoStats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

56
func metricMongoStats(ctx context.Context, appName, name string, labels []metrics.Label) {
57
        _, _ = utils.Catch(func() {
58
                var total, inuse int64
59
                _, err := utils.Catch(func() {
60
                        metricsPoolLocker.RLock()
61
                        defer metricsPoolLocker.RUnlock()
62
                        inuse = metricsPoolInUseCounter[appName][name].Load()
63
                        total = metricsPoolTotalCounter[appName][name].Load()
64
                })
65
                if err != nil {
66
                        return
67
                }
68
69
                app := config.Use(appName).AppName()
70
                idleKey := append([]string{app}, metricsPoolIdleKey...)
71
                inuseKey := append([]string{app}, metricsPoolInUseKey...)
72
                totalKey := append([]string{app}, metricsPoolTotalKey...)
73
                ide := total - inuse
74
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
75
                        select {
76
                        case <-ctx.Done():
77
                                return
78
                        default:
79
                                if m.IsEnableServiceLabel() {
80
                                        m.SetGauge(ctx, idleKey, float64(ide), metrics.Labels(labels))
81
                                        m.SetGauge(ctx, inuseKey, float64(inuse), metrics.Labels(labels))
82
                                        m.SetGauge(ctx, totalKey, float64(total), metrics.Labels(labels))
83
                                } else {
84
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(ide), metrics.Labels(labels))
85
                                        m.SetGauge(ctx, metricsPoolInUseKey, float64(inuse), metrics.Labels(labels))
86
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(total), metrics.Labels(labels))
87
                                }
88
                        }
89
                }
90
        })
91
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

71
func AppName(name string) utils.OptionFunc[useOption] {
72
        return func(o *useOption) {
73
                o.appName = name
74
        }
75
}
func WriteConcern
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

82
func WriteConcern(writeConcern *writeconcern.WriteConcern) utils.OptionFunc[useOption] {
83
        return func(o *useOption) {
84
                o.writeConcern = writeConcern
85
        }
86
}
func @72:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

72
func(o *useOption) {
73
                o.appName = name
74
        }
func instance.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

30
func (d *instance) GetProxy() *mgoDrv.Client {
31
        return d.mongo.GetProxy()
32
}
func instance.Database
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

34
func (d *instance) Database(opts ...*options.DatabaseOptions) *mgoDrv.Database {
35
        return d.mongo.Database(d.database, opts...)
36
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/construct.go:

51
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
52
        var monitor *mgoEvt.CommandMonitor
53
        if utils.IsStrNotBlank(conf.LoggerConfig.Logger) {
54
                loggerType := inspect.TypeOf(conf.LoggerConfig.Logger)
55
                loggerValue := reflect.New(loggerType)
56
                if loggerValue.Type().Implements(customLoggerType) {
57
                        l := fusLog.Use(conf.LoggerConfig.LogInstance, fusLog.AppName(opt.AppName))
58
                        loggerValue.Interface().(customLogger).Init(l, opt.AppName, name)
59
                }
60
                monitor = loggerValue.Interface().(logger).GetMonitor()
61
        }
62
63
        // conf.Option.Password = config.CryptoDecryptFunc()(conf.Option.Password)
64
        mgoCli, err := mongo.Default.New(ctx, conf.Option,
65
                mongo.WithMonitor(monitor),
66
                mongo.WithPoolMonitor(&mgoEvt.PoolMonitor{Event: metricsPoolMonitor(opt.AppName, name)}))
67
        if err != nil {
68
                panic(err)
69
        }
70
71
        rwlock.Lock()
72
        defer rwlock.Unlock()
73
        if appInstances == nil {
74
                appInstances = make(map[string]map[string]*instance)
75
        }
76
        if appInstances[opt.AppName] == nil {
77
                appInstances[opt.AppName] = make(map[string]*instance)
78
        }
79
        if _, ok := appInstances[opt.AppName][name]; ok {
80
                panic(ErrDuplicatedName)
81
        }
82
        appInstances[opt.AppName][name] = &instance{mongo: mgoCli, name: name, database: conf.DB}
83
84
        // ioc
85
        if opt.DI != nil {
86
                opt.DI.MustProvide(
87
                        func() *mgoDrv.Database {
88
                                return Use(name, AppName(opt.AppName)).Database
89
                        },
90
                        di.Name(name),
91
                )
92
        }
93
94
        go startDaemonRoutines(ctx, opt.AppName, name, conf)
95
}
func @33:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/construct.go:

33
func() {
34
                rwlock.Lock()
35
                defer rwlock.Unlock()
36
37
                pid := syscall.Getpid()
38
                app := config.Use(opt.AppName).AppName()
39
                if appInstances != nil {
40
                        for name, instance := range appInstances[opt.AppName] {
41
                                if err := instance.GetProxy().Disconnect(nil); err != nil {
42
                                        log.Printf("%v [Gofusion] %s %s %s disconnect error: %s",
43
                                                pid, app, config.ComponentMongo, name, err)
44
                                }
45
                        }
46
                        delete(appInstances, opt.AppName)
47
                }
48
        }
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

103
func Use(name string, opts ...utils.OptionExtender) *Mongo {
104
        opt := utils.ApplyOptions[useOption](opts...)
105
        dbOpt := options.
106
                Database().
107
                SetReadConcern(opt.readConcern).
108
                SetWriteConcern(opt.writeConcern).
109
                SetReadPreference(opt.readPreference).
110
                SetBSONOptions(opt.bsonOptions).
111
                SetRegistry(opt.registry)
112
113
        rwlock.RLock()
114
        defer rwlock.RUnlock()
115
        instances, ok := appInstances[opt.appName]
116
        if !ok {
117
                panic(fmt.Errorf("mongo database instance not found for app: %s", opt.appName))
118
        }
119
        instance, ok := instances[name]
120
        if !ok {
121
                panic(fmt.Errorf("mongo database instance not found for name: %s", name))
122
        }
123
        return &Mongo{Database: instance.Database(dbOpt), Name: name}
124
}
func metricMongoLatency
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

93
func metricMongoLatency(ctx context.Context, appName, name string, labels []metrics.Label) {
94
        select {
95
        case <-ctx.Done():
96
                return
97
        default:
98
99
        }
100
101
        _, _ = utils.Catch(func() {
102
                rwlock.RLock()
103
                defer rwlock.RUnlock()
104
                instances, ok := appInstances[appName]
105
                if !ok {
106
                        return
107
                }
108
                instance, ok := instances[name]
109
                if !ok {
110
                        return
111
                }
112
113
                mgoCli := instance.GetProxy()
114
                begin := time.Now()
115
                if err := mgoCli.Ping(ctx, nil); err != nil {
116
                        return
117
                }
118
119
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
120
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
121
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
122
                        select {
123
                        case <-ctx.Done():
124
                                return
125
                        default:
126
                                if m.IsEnableServiceLabel() {
127
                                        m.AddSample(ctx, latencyKey, latency,
128
                                                metrics.Labels(labels),
129
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
130
                                        )
131
                                } else {
132
                                        m.AddSample(ctx, metricsLatencyKey, latency,
133
                                                metrics.Labels(labels),
134
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
135
                                        )
136
                                }
137
                        }
138
                }
139
        })
140
}
func @101:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

101
func() {
102
                rwlock.RLock()
103
                defer rwlock.RUnlock()
104
                instances, ok := appInstances[appName]
105
                if !ok {
106
                        return
107
                }
108
                instance, ok := instances[name]
109
                if !ok {
110
                        return
111
                }
112
113
                mgoCli := instance.GetProxy()
114
                begin := time.Now()
115
                if err := mgoCli.Ping(ctx, nil); err != nil {
116
                        return
117
                }
118
119
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
120
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
121
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
122
                        select {
123
                        case <-ctx.Done():
124
                                return
125
                        default:
126
                                if m.IsEnableServiceLabel() {
127
                                        m.AddSample(ctx, latencyKey, latency,
128
                                                metrics.Labels(labels),
129
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
130
                                        )
131
                                } else {
132
                                        m.AddSample(ctx, metricsLatencyKey, latency,
133
                                                metrics.Labels(labels),
134
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
135
                                        )
136
                                }
137
                        }
138
                }
139
        }
func @57:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/metrics.go:

57
func() {
58
                var total, inuse int64
59
                _, err := utils.Catch(func() {
60
                        metricsPoolLocker.RLock()
61
                        defer metricsPoolLocker.RUnlock()
62
                        inuse = metricsPoolInUseCounter[appName][name].Load()
63
                        total = metricsPoolTotalCounter[appName][name].Load()
64
                })
65
                if err != nil {
66
                        return
67
                }
68
69
                app := config.Use(appName).AppName()
70
                idleKey := append([]string{app}, metricsPoolIdleKey...)
71
                inuseKey := append([]string{app}, metricsPoolInUseKey...)
72
                totalKey := append([]string{app}, metricsPoolTotalKey...)
73
                ide := total - inuse
74
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
75
                        select {
76
                        case <-ctx.Done():
77
                                return
78
                        default:
79
                                if m.IsEnableServiceLabel() {
80
                                        m.SetGauge(ctx, idleKey, float64(ide), metrics.Labels(labels))
81
                                        m.SetGauge(ctx, inuseKey, float64(inuse), metrics.Labels(labels))
82
                                        m.SetGauge(ctx, totalKey, float64(total), metrics.Labels(labels))
83
                                } else {
84
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(ide), metrics.Labels(labels))
85
                                        m.SetGauge(ctx, metricsPoolInUseKey, float64(inuse), metrics.Labels(labels))
86
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(total), metrics.Labels(labels))
87
                                }
88
                        }
89
                }
90
        }
func @87:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/construct.go:

87
func() *mgoDrv.Database {
88
                                return Use(name, AppName(opt.AppName)).Database
89
                        }
func ReadConcern
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

77
func ReadConcern(readConcern *readconcern.ReadConcern) utils.OptionFunc[useOption] {
78
        return func(o *useOption) {
79
                o.readConcern = readConcern
80
        }
81
}
func @78:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

78
func(o *useOption) {
79
                o.readConcern = readConcern
80
        }
func @88:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

88
func(o *useOption) {
89
                o.readPreference = readPreference
90
        }
func BsonOptions
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

92
func BsonOptions(bsonOptions *options.BSONOptions) utils.OptionFunc[useOption] {
93
        return func(o *useOption) {
94
                o.bsonOptions = bsonOptions
95
        }
96
}
func @93:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

93
func(o *useOption) {
94
                o.bsonOptions = bsonOptions
95
        }
func Registry
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

97
func Registry(registry *bsoncodec.Registry) utils.OptionFunc[useOption] {
98
        return func(o *useOption) {
99
                o.registry = registry
100
        }
101
}
func @98:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

98
func(o *useOption) {
99
                o.registry = registry
100
        }
func ReadPreference
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mongo/mongo.go:

87
func ReadPreference(readPreference *readpref.ReadPref) utils.OptionFunc[useOption] {
88
        return func(o *useOption) {
89
                o.readPreference = readPreference
90
        }
91
}
Package Overview: github.com/wfusion/gofusion/mq 62.1%

Please select a function to see what's left for testing.

NewEventSubscriber(...) github.com/wfusion/gofusion/mq/event.go 100.0% 9/9
router.Handle(...) github.com/wfusion/gofusion/mq/router.go 100.0% 7/7
newGoChannel(...) github.com/wfusion/gofusion/mq/gochannel.go 100.0% 7/7
newPostgres(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 7/7
Construct(...) github.com/wfusion/gofusion/mq/construct.go 100.0% 7/7
newMysql(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 7/7
newRedis(...) github.com/wfusion/gofusion/mq/redis.go 100.0% 6/6
router.runEventHandlers(...) github.com/wfusion/gofusion/mq/router.go 100.0% 6/6
eventSubscriber[T].SubscribeEvent(...) github.com/wfusion/gofusion/mq/event.go 100.0% 5/5
newAMQP(...) github.com/wfusion/gofusion/mq/amqp.go 100.0% 5/5
newKafka(...) github.com/wfusion/gofusion/mq/kafka.go 100.0% 5/5
newPulsar(...) github.com/wfusion/gofusion/mq/pulsar.go 100.0% 5/5
newSub(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 4/4
NewEventPublisher(...) github.com/wfusion/gofusion/mq/event.go 100.0% 4/4
newPub(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 4/4
messageConvertTo(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 2/2
isEventHandler(...) github.com/wfusion/gofusion/mq/event.go 100.0% 2/2
@182:9(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/mq/construct.go 100.0% 1/1
abstractMQ.watermillSubscriber(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 1/1
mysqlPublisher.close(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 1/1
EventHandler(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@48:9(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
EventHandlerWithMsg(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@55:9(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@172:9(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
Events(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
@42:31(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 1/1
event[T].ID(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@161:9(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
messages(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
ChannelLen(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
@179:9(...) github.com/wfusion/gofusion/mq/construct.go 100.0% 1/1
@158:9(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
Messages(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
UntimedEvent(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/mq/construct.go 100.0% 1/1
router.close(...) github.com/wfusion/gofusion/mq/router.go 100.0% 1/1
abstractMQ.topic(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 1/1
newEvent(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@80:31(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 1/1
event[T].Type(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
event[T].Payload(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@86:38(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 1/1
handleEventSubscriber(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
router.addEventDispatchHandler(...) github.com/wfusion/gofusion/mq/router.go 100.0% 1/1
event[T].Context(...) github.com/wfusion/gofusion/mq/event.go 100.0% 1/1
@192:9(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
rawMessageConvertFrom(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 1/1
NewMessage(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
_AMQPSubscriber.close(...) github.com/wfusion/gofusion/mq/amqp.go 100.0% 1/1
goChannel.close(...) github.com/wfusion/gofusion/mq/gochannel.go 100.0% 1/1
message.ID(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
@42:31(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 1/1
kafkaPublisher.close(...) github.com/wfusion/gofusion/mq/kafka.go 100.0% 1/1
postgresPublisher.close(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 1/1
kafkaSubscriber.close(...) github.com/wfusion/gofusion/mq/kafka.go 100.0% 1/1
@80:31(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 1/1
redisSubscriber.close(...) github.com/wfusion/gofusion/mq/redis.go 100.0% 1/1
@86:38(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 1/1
redisPublisher.close(...) github.com/wfusion/gofusion/mq/redis.go 100.0% 1/1
abstractMQ.watermillPublisher(...) github.com/wfusion/gofusion/mq/mq.go 100.0% 1/1
postgresSubscriber.close(...) github.com/wfusion/gofusion/mq/postgres.go 100.0% 1/1
_AMQPPublisher.close(...) github.com/wfusion/gofusion/mq/amqp.go 100.0% 1/1
pulsarSubscriber.close(...) github.com/wfusion/gofusion/mq/pulsar.go 100.0% 1/1
message.Payload(...) github.com/wfusion/gofusion/mq/types.go 100.0% 1/1
router.Running(...) github.com/wfusion/gofusion/mq/router.go 100.0% 1/1
pulsarPublisher.close(...) github.com/wfusion/gofusion/mq/pulsar.go 100.0% 1/1
mysqlSubscriber.close(...) github.com/wfusion/gofusion/mq/mysql.go 100.0% 1/1
@395:6(...) github.com/wfusion/gofusion/mq/router.go 92.9% 13/14
eventPublisher[T].PublishEvent(...) github.com/wfusion/gofusion/mq/event.go 91.7% 11/12
router.handleEvent(...) github.com/wfusion/gofusion/mq/router.go 89.5% 17/19
@41:9(...) github.com/wfusion/gofusion/mq/construct.go 88.0% 22/25
@370:3(...) github.com/wfusion/gofusion/mq/router.go 86.2% 25/29
formatEventHandlerSignature(...) github.com/wfusion/gofusion/mq/event.go 85.7% 6/7
@278:5(...) github.com/wfusion/gofusion/mq/router.go 85.7% 6/7
abstractMQ.SubscribeRaw(...) github.com/wfusion/gofusion/mq/mq.go 85.7% 6/7
addInstance(...) github.com/wfusion/gofusion/mq/construct.go 84.1% 37/44
router.isHandlerConflict(...) github.com/wfusion/gofusion/mq/router.go 83.3% 5/6
Sub(...) github.com/wfusion/gofusion/mq/construct.go 80.0% 8/10
Pub(...) github.com/wfusion/gofusion/mq/construct.go 80.0% 8/10
Use(...) github.com/wfusion/gofusion/mq/construct.go 80.0% 8/10
newRedisPublisher(...) github.com/wfusion/gofusion/mq/redis.go 80.0% 4/5
newMysqlSubscriber(...) github.com/wfusion/gofusion/mq/mysql.go 80.0% 4/5
newPostgresPublisher(...) github.com/wfusion/gofusion/mq/postgres.go 80.0% 4/5
newKafkaPublisher(...) github.com/wfusion/gofusion/mq/kafka.go 80.0% 4/5
router.Start(...) github.com/wfusion/gofusion/mq/router.go 80.0% 4/5
newRedisSubscriber(...) github.com/wfusion/gofusion/mq/redis.go 80.0% 4/5
newMysqlPublisher(...) github.com/wfusion/gofusion/mq/mysql.go 80.0% 4/5
newPostgresSubscriber(...) github.com/wfusion/gofusion/mq/postgres.go 80.0% 4/5
newAMQPPublisher(...) github.com/wfusion/gofusion/mq/amqp.go 78.6% 11/14
newAMQPSubscriber(...) github.com/wfusion/gofusion/mq/amqp.go 78.6% 11/14
newRouter(...) github.com/wfusion/gofusion/mq/router.go 75.0% 18/24
newPulsarPublisher(...) github.com/wfusion/gofusion/mq/pulsar.go 75.0% 9/12
abstractMQ.PublishRaw(...) github.com/wfusion/gofusion/mq/mq.go 71.4% 10/14
newKafkaSubscriber(...) github.com/wfusion/gofusion/mq/kafka.go 71.4% 5/7
abstractMQ.newObjectMessage(...) github.com/wfusion/gofusion/mq/mq.go 66.7% 8/12
router.run(...) github.com/wfusion/gofusion/mq/router.go 66.7% 4/6
event[T].Ack(...) github.com/wfusion/gofusion/mq/event.go 66.7% 2/3
parseKafkaConf(...) github.com/wfusion/gofusion/mq/kafka.go 64.0% 16/25
messageConvertFrom(...) github.com/wfusion/gofusion/mq/mq.go 63.6% 7/11
newPulsarSubscriber(...) github.com/wfusion/gofusion/mq/pulsar.go 60.0% 9/15
parseAMQPEndpoint(...) github.com/wfusion/gofusion/mq/amqp.go 54.5% 6/11
@146:13(...) github.com/wfusion/gofusion/mq/mq.go 46.7% 7/15
router.addHandler(...) github.com/wfusion/gofusion/mq/router.go 45.5% 5/11
abstractMQ.Publish(...) github.com/wfusion/gofusion/mq/mq.go 36.8% 7/19
@129:26(...) github.com/wfusion/gofusion/mq/event.go 25.0% 3/12
@188:13(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/25
setParams(...) github.com/wfusion/gofusion/mq/utils.go 0.0% 0/12
formatFields(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/10
sub(...) github.com/wfusion/gofusion/mq/construct.go 0.0% 0/10
router.Serve(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/8
wrapParams(...) github.com/wfusion/gofusion/mq/utils.go 0.0% 0/7
abstractMQ.newMessage(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/7
abstractMQ.Subscribe(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/7
@340:9(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/6
@117:19(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/5
@78:19(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/5
@113:18(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/5
event[T].toTime(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/5
@220:4(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/4
event[T].Nack(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/3
@120:16(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/3
@150:9(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/3
@81:16(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/3
router.handle(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/3
unwrapParams(...) github.com/wfusion/gofusion/mq/utils.go 0.0% 0/3
@166:9(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/2
@252:5(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/2
@264:5(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/2
formatLogMsg(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/2
event[T].DeletedAt(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
logDebug(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/1
@79:38(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/1
@118:38(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/1
@133:19(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/1
event[T].UpdatedAt(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
event[T].CreatedAt(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
EventDeleted(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
EventUpdated(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
Objects(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/1
EventCreated(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
NewEvent(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
@150:17(...) github.com/wfusion/gofusion/mq/construct.go 0.0% 0/1
@102:9(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
NewEventSubscriberDI(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
Async(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/1
@130:20(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/1
@62:9(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
NewEventPublisherDI(...) github.com/wfusion/gofusion/mq/event.go 0.0% 0/1
@77:18(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/1
@169:23(...) github.com/wfusion/gofusion/mq/construct.go 0.0% 0/1
kafkaOAuthProvider.Token(...) github.com/wfusion/gofusion/mq/kafka.go 0.0% 0/1
@149:17(...) github.com/wfusion/gofusion/mq/construct.go 0.0% 0/1
abstractMQ.close(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/1
abstractMQ.watermillLogger(...) github.com/wfusion/gofusion/mq/mq.go 0.0% 0/1
logError(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/1
message.RawMessage(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/1
message.Object(...) github.com/wfusion/gofusion/mq/types.go 0.0% 0/1
logInfo(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/1
logTrace(...) github.com/wfusion/gofusion/mq/log.go 0.0% 0/1
@93:29(...) github.com/wfusion/gofusion/mq/router.go 0.0% 0/1
func NewEventSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

107
func NewEventSubscriber[T eventual](name string, opts ...utils.OptionExtender) EventSubscriber[T] {
108
        opt := utils.ApplyOptions[useOption](opts...)
109
        subscriber := Sub(name, AppName(opt.appName))
110
        abstractMq := inspect.GetField[*abstractMQ](subscriber, "abstractMQ")
111
112
        var m reflect.Value
113
        for tv := reflect.ValueOf(new(T)); tv.Kind() == reflect.Ptr; tv = tv.Elem() {
114
                if m = tv.MethodByName("EventType"); m.IsValid() {
115
                        break
116
                }
117
        }
118
        eventType := m.Call(nil)[0].String()
119
        return &eventSubscriber[T]{abstractMQ: abstractMq, evtType: eventType}
120
}
func router.Handle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

161
func (r *router) Handle(handlerName string, hdr any, opts ...utils.OptionExtender) {
162
        opt := utils.ApplyOptions[routerOption](opts...)
163
        if opt.isEventSubscriber || singleConsumerMQType.Contains(r.c.Type) {
164
                r.addHandler(handlerName, handlerName, hdr, opt)
165
                return
166
        }
167
        for i := 0; i < r.c.ConsumerConcurrency; i++ {
168
                consumerName := fmt.Sprintf("%s_%v", handlerName, i)
169
                r.addHandler(handlerName, consumerName, hdr, opt)
170
        }
171
}
func newGoChannel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/gochannel.go:

11
func newGoChannel(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
12
        pub Publisher, sub Subscriber) {
13
        cfg := gochannel.Config{
14
                OutputChannelBuffer:            int64(conf.ConsumerConcurrency),
15
                Persistent:                     conf.Persistent,
16
                ConsumerGroup:                  conf.ConsumerGroup,
17
                BlockPublishUntilSubscriberAck: false,
18
                AppID:                          config.Use(appName).AppName(),
19
        }
20
21
        native := gochannel.NewGoChannel(cfg, logger)
22
        if conf.Producer {
23
                pub = &goChannel{
24
                        abstractMQ: newPub(ctx, native, appName, name, conf, logger),
25
                        ch:         native,
26
                }
27
        }
28
29
        if conf.Consumer {
30
                sub = &goChannel{
31
                        abstractMQ: newSub(ctx, native, appName, name, conf, logger),
32
                        ch:         native,
33
                }
34
        }
35
        return
36
}
func newPostgres
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

18
func newPostgres(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
19
        pub Publisher, sub Subscriber) {
20
        instance := db.Use(ctx, conf.Endpoint.Instance, db.AppName(appName))
21
        cli := utils.Must(instance.GetProxy().DB())
22
        if conf.Producer {
23
                pub = newPostgresPublisher(ctx, appName, name, conf, logger, cli)
24
        }
25
26
        if conf.Consumer {
27
                sub = newPostgresSubscriber(ctx, appName, name, conf, logger, cli)
28
        }
29
30
        return
31
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

30
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
31
        opt := utils.ApplyOptions[config.InitOption](opts...)
32
        optU := utils.ApplyOptions[useOption](opts...)
33
        if opt.AppName == "" {
34
                opt.AppName = optU.appName
35
        }
36
37
        for name, conf := range confs {
38
                addInstance(ctx, name, conf, opt)
39
        }
40
41
        return func() {
42
                locker.Lock()
43
                defer locker.Unlock()
44
45
                pid := syscall.Getpid()
46
                app := config.Use(opt.AppName).AppName()
47
                if routers != nil {
48
                        for name, router := range routers[opt.AppName] {
49
                                log.Printf("%v [Gofusion] %s %s %s router exiting...",
50
                                        pid, app, config.ComponentMessageQueue, name)
51
                                if err := router.close(); err == nil {
52
                                        log.Printf("%v [Gofusion] %s %s %s router exited",
53
                                                pid, app, config.ComponentMessageQueue, name)
54
                                } else {
55
                                        log.Printf("%v [Gofusion] %s %s %s router exit failed: %s",
56
                                                pid, app, config.ComponentMessageQueue, name, err)
57
                                }
58
                        }
59
                        delete(routers, opt.AppName)
60
                }
61
62
                if publishers != nil {
63
                        for name, publisher := range publishers[opt.AppName] {
64
                                log.Printf("%v [Gofusion] %s %s %s publisher exiting...",
65
                                        pid, app, config.ComponentMessageQueue, name)
66
                                if err := publisher.close(); err == nil {
67
                                        log.Printf("%v [Gofusion] %s %s %s publisher exited",
68
                                                pid, app, config.ComponentMessageQueue, name)
69
                                } else {
70
                                        log.Printf("%v [Gofusion] %s %s %s publisher exit failed: %s",
71
                                                pid, app, config.ComponentMessageQueue, name, err)
72
                                }
73
                        }
74
                        delete(publishers, opt.AppName)
75
                }
76
77
                if subscribers != nil {
78
                        for name, subscriber := range subscribers[opt.AppName] {
79
                                log.Printf("%v [Gofusion] %s %s %s subscriber exiting...",
80
                                        pid, app, config.ComponentMessageQueue, name)
81
                                if err := subscriber.close(); err == nil {
82
                                        log.Printf("%v [Gofusion] %s %s %s subscriber exited",
83
                                                pid, app, config.ComponentMessageQueue, name)
84
                                } else {
85
                                        log.Printf("%v [Gofusion] %s %s %s subscriber exit failed: %s",
86
                                                pid, app, config.ComponentMessageQueue, name, err)
87
                                }
88
                        }
89
                        delete(subscribers, opt.AppName)
90
                }
91
        }
92
}
func newMysql
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

18
func newMysql(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
19
        pub Publisher, sub Subscriber) {
20
        instance := db.Use(ctx, conf.Endpoint.Instance, db.AppName(appName))
21
        cli := utils.Must(instance.GetProxy().DB())
22
        if conf.Producer {
23
                pub = newMysqlPublisher(ctx, appName, name, conf, logger, cli)
24
        }
25
26
        if conf.Consumer {
27
                sub = newMysqlSubscriber(ctx, appName, name, conf, logger, cli)
28
        }
29
30
        return
31
}
func newRedis
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/redis.go:

17
func newRedis(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
18
        pub Publisher, sub Subscriber) {
19
20
        cli := redis.Use(ctx, conf.Endpoint.Instance, redis.AppName(appName))
21
22
        if conf.Producer {
23
                pub = newRedisPublisher(ctx, appName, name, conf, logger, cli)
24
        }
25
26
        if conf.Consumer {
27
                sub = newRedisSubscriber(ctx, appName, name, conf, logger, cli)
28
        }
29
30
        return
31
}
func router.runEventHandlers
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

352
func (r *router) runEventHandlers() {
353
        if singleConsumerMQType.Contains(r.c.Type) {
354
                r.addEventDispatchHandler(defaultRouterEventHandlerName)
355
                return
356
        }
357
        for i := 0; i < r.c.ConsumerConcurrency; i++ {
358
                consumerName := fmt.Sprintf("%s_%v", defaultRouterEventHandlerName, i)
359
                r.addEventDispatchHandler(consumerName)
360
        }
361
}
func eventSubscriber[T].SubscribeEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

122
func (e *eventSubscriber[T]) SubscribeEvent(ctx context.Context, opts ...utils.OptionExtender) (
123
        dst <-chan Event[T], err error) {
124
        opt := utils.ApplyOptions[subOption](opts...)
125
        out := make(chan Event[T], opt.channelLength)
126
        r := Use(e.name, AppName(e.appName)).(*router)
127
        r.Handle(
128
                e.evtType,
129
                EventHandlerWithMsg[T](func(ctx context.Context, event Event[T]) (msgs []Message, err error) {
130
                        select {
131
                        case out <- event:
132
                        case <-r.Router.ClosingInProgressCh:
133
                                event.Nack()
134
                                e.logger.Info(fmt.Sprintf("event subscriber %s exited", e.name), nil)
135
                                return
136
                        case <-ctx.Done():
137
                                event.Nack()
138
                                e.logger.Info(fmt.Sprintf(
139
                                        "event subscriber %s exited with a message nacked when business ctx done", e.name),
140
                                        watermill.LogFields{watermill.ContextLogFieldKey: ctx})
141
                                return
142
                        case <-e.ctx.Done():
143
                                event.Nack()
144
                                e.logger.Info(fmt.Sprintf(
145
                                        "event subscriber %s exited with a message nacked when app ctx done", e.name),
146
                                        watermill.LogFields{watermill.ContextLogFieldKey: ctx})
147
                                return
148
                        }
149
150
                        msgs = append(msgs,
151
                                &message{Message: &mw.Message{Metadata: mw.Metadata{watermill.MessageRouterAck: ""}}})
152
                        return
153
                }),
154
                handleEventSubscriber(),
155
        )
156
        return out, err
157
}
func newAMQP
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

16
func newAMQP(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
17
        pub Publisher, sub Subscriber) {
18
        if conf.Producer {
19
                pub = newAMQPPublisher(ctx, appName, name, conf, logger)
20
        }
21
22
        if conf.Consumer {
23
                sub = newAMQPSubscriber(ctx, appName, name, conf, logger)
24
        }
25
26
        return
27
}
func newKafka
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

17
func newKafka(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
18
        pub Publisher, sub Subscriber) {
19
        if conf.Producer {
20
                pub = newKafkaPublisher(ctx, appName, name, conf, logger)
21
        }
22
23
        if conf.Consumer {
24
                sub = newKafkaSubscriber(ctx, appName, name, conf, logger)
25
        }
26
27
        return
28
}
func newPulsar
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/pulsar.go:

18
func newPulsar(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) (
19
        pub Publisher, sub Subscriber) {
20
        if conf.Producer {
21
                pub = newPulsarPublisher(ctx, appName, name, conf, logger)
22
        }
23
24
        if conf.Consumer {
25
                sub = newPulsarSubscriber(ctx, appName, name, conf, logger)
26
        }
27
28
        return
29
}
func newSub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

44
func newSub(ctx context.Context, sub mw.Subscriber, appName, name string,
45
        conf *Conf, logger watermill.LoggerAdapter) *abstractMQ {
46
        mq := &abstractMQ{ctx: ctx, sub: sub, appName: appName, name: name, conf: clone.Slowly(conf), logger: logger}
47
        mq.serializeType = serialize.ParseAlgorithm(conf.SerializeType)
48
        mq.compressType = compress.ParseAlgorithm(conf.CompressType)
49
        return mq
50
}
func NewEventPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

67
func NewEventPublisher[T eventual](name string, opts ...utils.OptionExtender) EventPublisher[T] {
68
        opt := utils.ApplyOptions[useOption](opts...)
69
        publisher := Pub(name, AppName(opt.appName))
70
        abstractMq := inspect.GetField[*abstractMQ](publisher, "abstractMQ")
71
        return &eventPublisher[T]{abstractMQ: abstractMq}
72
}
func newPub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

36
func newPub(ctx context.Context, pub mw.Publisher, appName, name string,
37
        conf *Conf, logger watermill.LoggerAdapter) *abstractMQ {
38
        mq := &abstractMQ{ctx: ctx, pub: pub, appName: appName, name: name, conf: clone.Slowly(conf), logger: logger}
39
        mq.serializeType = serialize.ParseAlgorithm(conf.SerializeType)
40
        mq.compressType = compress.ParseAlgorithm(conf.CompressType)
41
        return mq
42
}
func messageConvertTo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

280
func messageConvertTo(src Message) (dst *mw.Message) {
281
        dst = src.(*message).Message
282
        return
283
}
func isEventHandler
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

26
func isEventHandler(f any) bool {
27
        sig := formatEventHandlerSignature(f)
28
        return strings.HasPrefix(sig, eventHandlerSignature) || strings.HasPrefix(sig, eventHandlerWithMsgSignature)
29
}
func @182:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

182
func(o *subOption) {
183
                o.channelLength = channelLength
184
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

248
func init() {
249
        config.AddComponent(config.ComponentMessageQueue, Construct)
250
}
func abstractMQ.watermillSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

244
func (a *abstractMQ) watermillSubscriber() mw.Subscriber       { return a.sub }
func mysqlPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

62
func (m *mysqlPublisher) close() (err error) {
63
        return m.publisher.Close()
64
}
func EventHandler
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

47
func EventHandler[T eventual](hdr eventHandler[T]) eventHandler[T] {
48
        return func(ctx context.Context, event Event[T]) error {
49
                // TODO: dedup & discard expired event
50
                return hdr(ctx, event)
51
        }
52
}
func @48:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

48
func(ctx context.Context, event Event[T]) error {
49
                // TODO: dedup & discard expired event
50
                return hdr(ctx, event)
51
        }
func EventHandlerWithMsg
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

54
func EventHandlerWithMsg[T eventual](hdr eventHandlerWithMsg[T]) eventHandlerWithMsg[T] {
55
        return func(ctx context.Context, event Event[T]) ([]Message, error) {
56
                // TODO: dedup & discard expired event
57
                return hdr(ctx, event)
58
        }
59
}
func @55:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

55
func(ctx context.Context, event Event[T]) ([]Message, error) {
56
                // TODO: dedup & discard expired event
57
                return hdr(ctx, event)
58
        }
func @172:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

172
func(o *eventPubOption[T]) {
173
                o.events = events
174
        }
func Events
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

171
func Events[T eventual](events ...Event[T]) utils.OptionFunc[eventPubOption[T]] {
172
        return func(o *eventPubOption[T]) {
173
                o.events = events
174
        }
175
}
func @42:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

42
func(topic string) string {
43
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
44
                        }
func event[T].ID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

223
func (e *event[T]) ID() string               { return e.pd.I }
func @161:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

161
func(o *pubOption) {
162
                o.watermillMessages = messages
163
        }
func messages
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

160
func messages(messages ...*mw.Message) utils.OptionFunc[pubOption] {
161
        return func(o *pubOption) {
162
                o.watermillMessages = messages
163
        }
164
}
func ChannelLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

181
func ChannelLen(channelLength int) utils.OptionFunc[subOption] {
182
        return func(o *subOption) {
183
                o.channelLength = channelLength
184
        }
185
}
func @179:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

179
func(o *useOption) {
180
                o.appName = name
181
        }
func @158:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

158
func(o *pubOption) { o.messages = messages }
func Messages
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

157
func Messages(messages ...Message) utils.OptionFunc[pubOption] {
158
        return func(o *pubOption) { o.messages = messages }
159
}
func UntimedEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

175
func UntimedEvent[T eventual](id string, payload T) Event[T] {
176
        return newEvent[T](id, time.Time{}, time.Time{}, time.Time{}, payload)
177
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

178
func AppName(name string) utils.OptionFunc[useOption] {
179
        return func(o *useOption) {
180
                o.appName = name
181
        }
182
}
func router.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

455
func (r *router) close() (err error) {
456
        return r.Close()
457
}
func abstractMQ.topic
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

242
func (a *abstractMQ) topic() string                            { return a.conf.Topic }
func newEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

207
func newEvent[T eventual](id string, createdAt, updatedAt, deletedAt time.Time, payload T) Event[T] {
208
        return &event[T]{
209
                pd: &eventPayload[T]{
210
                        I:  id,
211
                        T:  payload.EventType(),
212
                        P:  payload,
213
                        C:  createdAt.Format(time.RFC3339Nano),
214
                        CL: createdAt.Location().String(),
215
                        U:  updatedAt.Format(time.RFC3339Nano),
216
                        UL: updatedAt.Location().String(),
217
                        D:  deletedAt.Format(time.RFC3339Nano),
218
                        DL: deletedAt.Location().String(),
219
                        N:  time.Now().UnixNano(),
220
                },
221
        }
222
}
func @80:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

80
func(topic string) string {
81
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
82
                        }
func event[T].Type
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

224
func (e *event[T]) Type() string             { return e.pd.T }
func event[T].Payload
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

225
func (e *event[T]) Payload() T               { return e.pd.P }
func @86:38
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

86
func(topic string) string {
87
                                return fmt.Sprintf("%s_offsets_%s", conf.MessageScheme, topic)
88
                        }
func handleEventSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

191
func handleEventSubscriber() utils.OptionFunc[routerOption] {
192
        return func(o *routerOption) {
193
                o.isEventSubscriber = true
194
        }
195
}
func router.addEventDispatchHandler
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

363
func (r *router) addEventDispatchHandler(consumerName string) {
364
        r.Router.AddHandler(
365
                consumerName,
366
                r.sub.topic(),
367
                r.sub.watermillSubscriber(),
368
                r.pub.topic(),
369
                r.pub.watermillPublisher(),
370
                func(msg *mw.Message) (pubMsgs []*mw.Message, err error) {
371
                        eventType := msg.Metadata[keyEventType]
372
                        r.locker.RLock()
373
                        hdr, ok1 := r.eventHandlers[eventType]
374
                        subhdr, ok2 := r.eventSubscriberHandlers[eventType]
375
                        r.locker.RUnlock()
376
                        if !ok1 && !ok2 {
377
                                rawID := "unknown"
378
                                if msg.Metadata != nil {
379
                                        rawID = msg.Metadata[watermill.ContextKeyRawMessageID]
380
                                }
381
                                return nil, errors.Errorf(
382
                                        "handle unknown event message [type[%s] message_uuid[%s] message_raw_id[%s]]",
383
                                        eventType, msg.UUID, rawID)
384
                        }
385
                        handlers := []*handler{hdr, subhdr}
386
387
                        wg := new(sync.WaitGroup)
388
                        futures := make([]*routine.Future, 0, len(handlers))
389
                        for _, hdr := range handlers {
390
                                if hdr == nil {
391
                                        continue
392
                                }
393
                                wg.Add(1)
394
                                f := routine.Promise(
395
                                        func(hdr handler) (msgs any, err error) {
396
                                                _, data, _, err := pd.Unseal(msg.Payload,
397
                                                        pd.Serialize(r.serializeType), pd.Compress(r.compressType), pd.Type(hdr.evtPayloadType))
398
                                                if err != nil {
399
                                                        return
400
                                                }
401
                                                event := reflect.New(hdr.evtType).Interface()
402
                                                inspect.SetField(event, "pd", data)
403
404
                                                ctx := fusCtx.New(fusCtx.Watermill(msg.Metadata))
405
                                                ctx = log.SetContextFields(ctx, log.Fields{
406
                                                        keyEntityID:  msg.Metadata[keyEntityID],
407
                                                        keyEventType: msg.Metadata[keyEventType],
408
                                                })
409
                                                inspect.SetField(event, "ctx", ctx)
410
                                                inspect.SetField(event, "ackfn", msg.Ack)
411
                                                inspect.SetField(event, "nackfn", msg.Nack)
412
413
                                                rets := hdr.fn.Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(event)})
414
                                                msgs = utils.ParseVariadicFuncResult[[]Message](rets, 0)
415
                                                err = utils.ParseVariadicFuncResult[error](rets, 0)
416
                                                return
417
                                        },
418
                                        true,
419
                                        routine.Args(hdr),
420
                                        routine.WaitGroup(wg),
421
                                        routine.AppName(r.appName),
422
                                )
423
                                futures = append(futures, f)
424
                        }
425
                        wg.Wait()
426
427
                        pubMsgs = make([]*mw.Message, 0, len(handlers))
428
                        for _, f := range futures {
429
                                msgsAny, msgErr := f.Get()
430
                                err = multierr.Append(err, msgErr)
431
                                if msgsAny != nil {
432
                                        msgs, _ := msgsAny.([]Message)
433
                                        for _, m := range msgs {
434
                                                pubMsgs = append(pubMsgs, messageConvertTo(m))
435
                                        }
436
                                }
437
                        }
438
                        return
439
                },
440
        )
441
}
func event[T].Context
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

229
func (e *event[T]) Context() context.Context { return e.ctx }
func @192:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

192
func(o *routerOption) {
193
                o.isEventSubscriber = true
194
        }
func rawMessageConvertFrom
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

276
func rawMessageConvertFrom(src *mw.Message) (dst Message) {
277
        return &message{Message: src, payload: src.Payload}
278
}
func NewMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

204
func NewMessage(uuid string, payload []byte) Message {
205
        return &message{Message: mw.NewMessage(uuid, payload), payload: payload}
206
}
func _AMQPSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

106
func (a *_AMQPSubscriber) close() (err error) {
107
        return a.subscriber.Close()
108
}
func goChannel.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/gochannel.go:

43
func (g *goChannel) close() (err error) { return g.ch.Close() }
func message.ID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

207
func (m *message) ID() string      { return m.Message.UUID }
func @42:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

42
func(topic string) string {
43
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
44
                        }
func kafkaPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

54
func (k *kafkaPublisher) close() (err error) {
55
        return k.publisher.Close()
56
}
func postgresPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

62
func (p *postgresPublisher) close() (err error) {
63
        return p.publisher.Close()
64
}
func kafkaSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

95
func (k *kafkaSubscriber) close() (err error) {
96
        return k.subscriber.Close()
97
}
func @80:31
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

80
func(topic string) string {
81
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
82
                        }
func redisSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/redis.go:

97
func (r *redisSubscriber) close() (err error) {
98
        return r.subscriber.Close()
99
}
func @86:38
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

86
func(topic string) string {
87
                                return fmt.Sprintf("%s_offsets_%s", conf.MessageScheme, topic)
88
                        }
func redisPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/redis.go:

58
func (r *redisPublisher) close() (err error) {
59
        return r.publisher.Close()
60
}
func abstractMQ.watermillPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

243
func (a *abstractMQ) watermillPublisher() mw.Publisher         { return a.pub }
func postgresSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

105
func (p *postgresSubscriber) close() (err error) {
106
        return p.subscriber.Close()
107
}
func _AMQPPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

67
func (a *_AMQPPublisher) close() (err error) {
68
        return a.publisher.Close()
69
}
func pulsarSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/pulsar.go:

107
func (p *pulsarSubscriber) close() (err error) {
108
        return p.subscriber.Close()
109
}
func message.Payload
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

208
func (m *message) Payload() []byte { return m.payload }
func router.Running
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

197
func (r *router) Running() <-chan struct{} {
198
        return r.Router.Running()
199
}
func pulsarPublisher.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/pulsar.go:

63
func (p *pulsarPublisher) close() (err error) {
64
        return p.publisher.Close()
65
}
func mysqlSubscriber.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

105
func (m *mysqlSubscriber) close() (err error) {
106
        return m.subscriber.Close()
107
}
func @395:6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

395
func(hdr handler) (msgs any, err error) {
396
                                                _, data, _, err := pd.Unseal(msg.Payload,
397
                                                        pd.Serialize(r.serializeType), pd.Compress(r.compressType), pd.Type(hdr.evtPayloadType))
398
                                                if err != nil {
399
                                                        return
400
                                                }
401
                                                event := reflect.New(hdr.evtType).Interface()
402
                                                inspect.SetField(event, "pd", data)
403
404
                                                ctx := fusCtx.New(fusCtx.Watermill(msg.Metadata))
405
                                                ctx = log.SetContextFields(ctx, log.Fields{
406
                                                        keyEntityID:  msg.Metadata[keyEntityID],
407
                                                        keyEventType: msg.Metadata[keyEventType],
408
                                                })
409
                                                inspect.SetField(event, "ctx", ctx)
410
                                                inspect.SetField(event, "ackfn", msg.Ack)
411
                                                inspect.SetField(event, "nackfn", msg.Nack)
412
413
                                                rets := hdr.fn.Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(event)})
414
                                                msgs = utils.ParseVariadicFuncResult[[]Message](rets, 0)
415
                                                err = utils.ParseVariadicFuncResult[error](rets, 0)
416
                                                return
417
                                        }
func eventPublisher[T].PublishEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

78
func (e *eventPublisher[T]) PublishEvent(ctx context.Context, opts ...utils.OptionExtender) (err error) {
79
        opt := utils.ApplyOptions[pubOption](opts...)
80
        optT := utils.ApplyOptions[eventPubOption[T]](opts...)
81
        msgs := make([]*mw.Message, 0, len(optT.events))
82
        for _, evt := range optT.events {
83
                msg, err := e.abstractMQ.newObjectMessage(ctx, evt.(*event[T]).pd, opt)
84
                if msg != nil {
85
                        msg.Metadata[keyEntityID] = evt.ID()
86
                        msg.Metadata[keyEventType] = evt.Type()
87
                }
88
                if err != nil {
89
                        return err
90
                }
91
                msgs = append(msgs, msg)
92
        }
93
        return e.abstractMQ.Publish(ctx, messages(msgs...))
94
}
func router.handleEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

302
func (r *router) handleEvent(eventType string, fnVal reflect.Value, opt *routerOption) {
303
        // FIXME: Translating generics to corresponding implemented generic types like this is too hacky.
304
        //        If this set becomes invalid, switch to the implementation of event payload as any without generics,
305
        //        and the router can continue to provide it using the current method of storing reflect.Type.
306
        evtType := fnVal.Type().In(1)
307
        eventName := strings.Replace(evtType.Name(), "Event[", "event[", 1)
308
        eventTypeName := fmt.Sprintf(mqPackageSignFormat, eventName)
309
        et := inspect.TypeOf(eventTypeName)
310
        if et == nil {
311
                panic(errors.Errorf("unknown event generic object type: %s", eventTypeName))
312
        }
313
        eventPayloadName := strings.Replace(evtType.Name(), "Event[", "eventPayload[", 1)
314
        eventPayloadTypeName := fmt.Sprintf(mqPackageSignFormat, eventPayloadName)
315
        ept := inspect.TypeOf(eventPayloadTypeName)
316
        if ept == nil {
317
                panic(errors.Errorf("unknown event payload generic object type: %s", eventPayloadTypeName))
318
        }
319
320
        hdr := &handler{
321
                fn:             fnVal,
322
                evtType:        et,
323
                evtPayloadType: reflect.PtrTo(ept),
324
        }
325
326
        r.locker.Lock()
327
        defer r.locker.Unlock()
328
        if !opt.isEventSubscriber {
329
                r.eventHandlers[eventType] = hdr
330
        } else {
331
                r.eventSubscriberHandlers[eventType] = hdr
332
                r.addEventDispatchHandler(defaultRouterEventHandlerName + "_" + eventType)
333
                routine.Go(r.run, routine.AppName(r.appName))
334
        }
335
}
func @41:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

41
func() {
42
                locker.Lock()
43
                defer locker.Unlock()
44
45
                pid := syscall.Getpid()
46
                app := config.Use(opt.AppName).AppName()
47
                if routers != nil {
48
                        for name, router := range routers[opt.AppName] {
49
                                log.Printf("%v [Gofusion] %s %s %s router exiting...",
50
                                        pid, app, config.ComponentMessageQueue, name)
51
                                if err := router.close(); err == nil {
52
                                        log.Printf("%v [Gofusion] %s %s %s router exited",
53
                                                pid, app, config.ComponentMessageQueue, name)
54
                                } else {
55
                                        log.Printf("%v [Gofusion] %s %s %s router exit failed: %s",
56
                                                pid, app, config.ComponentMessageQueue, name, err)
57
                                }
58
                        }
59
                        delete(routers, opt.AppName)
60
                }
61
62
                if publishers != nil {
63
                        for name, publisher := range publishers[opt.AppName] {
64
                                log.Printf("%v [Gofusion] %s %s %s publisher exiting...",
65
                                        pid, app, config.ComponentMessageQueue, name)
66
                                if err := publisher.close(); err == nil {
67
                                        log.Printf("%v [Gofusion] %s %s %s publisher exited",
68
                                                pid, app, config.ComponentMessageQueue, name)
69
                                } else {
70
                                        log.Printf("%v [Gofusion] %s %s %s publisher exit failed: %s",
71
                                                pid, app, config.ComponentMessageQueue, name, err)
72
                                }
73
                        }
74
                        delete(publishers, opt.AppName)
75
                }
76
77
                if subscribers != nil {
78
                        for name, subscriber := range subscribers[opt.AppName] {
79
                                log.Printf("%v [Gofusion] %s %s %s subscriber exiting...",
80
                                        pid, app, config.ComponentMessageQueue, name)
81
                                if err := subscriber.close(); err == nil {
82
                                        log.Printf("%v [Gofusion] %s %s %s subscriber exited",
83
                                                pid, app, config.ComponentMessageQueue, name)
84
                                } else {
85
                                        log.Printf("%v [Gofusion] %s %s %s subscriber exit failed: %s",
86
                                                pid, app, config.ComponentMessageQueue, name, err)
87
                                }
88
                        }
89
                        delete(subscribers, opt.AppName)
90
                }
91
        }
func @370:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

370
func(msg *mw.Message) (pubMsgs []*mw.Message, err error) {
371
                        eventType := msg.Metadata[keyEventType]
372
                        r.locker.RLock()
373
                        hdr, ok1 := r.eventHandlers[eventType]
374
                        subhdr, ok2 := r.eventSubscriberHandlers[eventType]
375
                        r.locker.RUnlock()
376
                        if !ok1 && !ok2 {
377
                                rawID := "unknown"
378
                                if msg.Metadata != nil {
379
                                        rawID = msg.Metadata[watermill.ContextKeyRawMessageID]
380
                                }
381
                                return nil, errors.Errorf(
382
                                        "handle unknown event message [type[%s] message_uuid[%s] message_raw_id[%s]]",
383
                                        eventType, msg.UUID, rawID)
384
                        }
385
                        handlers := []*handler{hdr, subhdr}
386
387
                        wg := new(sync.WaitGroup)
388
                        futures := make([]*routine.Future, 0, len(handlers))
389
                        for _, hdr := range handlers {
390
                                if hdr == nil {
391
                                        continue
392
                                }
393
                                wg.Add(1)
394
                                f := routine.Promise(
395
                                        func(hdr handler) (msgs any, err error) {
396
                                                _, data, _, err := pd.Unseal(msg.Payload,
397
                                                        pd.Serialize(r.serializeType), pd.Compress(r.compressType), pd.Type(hdr.evtPayloadType))
398
                                                if err != nil {
399
                                                        return
400
                                                }
401
                                                event := reflect.New(hdr.evtType).Interface()
402
                                                inspect.SetField(event, "pd", data)
403
404
                                                ctx := fusCtx.New(fusCtx.Watermill(msg.Metadata))
405
                                                ctx = log.SetContextFields(ctx, log.Fields{
406
                                                        keyEntityID:  msg.Metadata[keyEntityID],
407
                                                        keyEventType: msg.Metadata[keyEventType],
408
                                                })
409
                                                inspect.SetField(event, "ctx", ctx)
410
                                                inspect.SetField(event, "ackfn", msg.Ack)
411
                                                inspect.SetField(event, "nackfn", msg.Nack)
412
413
                                                rets := hdr.fn.Call([]reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(event)})
414
                                                msgs = utils.ParseVariadicFuncResult[[]Message](rets, 0)
415
                                                err = utils.ParseVariadicFuncResult[error](rets, 0)
416
                                                return
417
                                        },
418
                                        true,
419
                                        routine.Args(hdr),
420
                                        routine.WaitGroup(wg),
421
                                        routine.AppName(r.appName),
422
                                )
423
                                futures = append(futures, f)
424
                        }
425
                        wg.Wait()
426
427
                        pubMsgs = make([]*mw.Message, 0, len(handlers))
428
                        for _, f := range futures {
429
                                msgsAny, msgErr := f.Get()
430
                                err = multierr.Append(err, msgErr)
431
                                if msgsAny != nil {
432
                                        msgs, _ := msgsAny.([]Message)
433
                                        for _, m := range msgs {
434
                                                pubMsgs = append(pubMsgs, messageConvertTo(m))
435
                                        }
436
                                }
437
                        }
438
                        return
439
                }
func formatEventHandlerSignature
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

30
func formatEventHandlerSignature(f any) string {
31
        ft, ok := f.(reflect.Type)
32
        if !ok {
33
                fv, ok := f.(reflect.Value)
34
                if ok {
35
                        ft = fv.Type()
36
                } else {
37
                        ft = reflect.TypeOf(f)
38
                }
39
        }
40
41
        return ft.PkgPath() + "." + ft.Name()
42
}
func @278:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

278
func(wmsg *mw.Message) (msgs []*mw.Message, err error) {
279
                                        msg, err := messageConvertFrom(wmsg, r.serializeType, r.compressType)
280
                                        if err != nil {
281
                                                return
282
                                        }
283
                                        rets := fnVal.Convert(handlerFuncType).Call([]reflect.Value{reflect.ValueOf(msg)})
284
                                        msgs = utils.ParseVariadicFuncResult[[]*mw.Message](rets, 0)
285
                                        err = utils.ParseVariadicFuncResult[error](rets, 0)
286
                                        return
287
                                }
func abstractMQ.SubscribeRaw
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

138
func (a *abstractMQ) SubscribeRaw(ctx context.Context, opts ...utils.OptionExtender) (dst <-chan Message, err error) {
139
        opt := utils.ApplyOptions[subOption](opts...)
140
        ch, err := a.sub.Subscribe(ctx, a.conf.Topic)
141
        if err != nil {
142
                return
143
        }
144
145
        msgCh := make(chan Message, opt.channelLength)
146
        routine.Go(func() {
147
                defer close(msgCh)
148
                for {
149
                        select {
150
                        case wmsg, ok := <-ch:
151
                                if !ok {
152
                                        return
153
                                }
154
                                msg := rawMessageConvertFrom(wmsg)
155
                                select {
156
                                case msgCh <- msg:
157
                                case <-ctx.Done():
158
                                        msg.Nack()
159
                                        a.logger.Info(fmt.Sprintf(
160
                                                "raw subscriber %s exited with a message nacked when business ctx done", a.name),
161
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
162
                                        return
163
                                case <-a.ctx.Done():
164
                                        msg.Nack()
165
                                        a.logger.Info(fmt.Sprintf(
166
                                                "raw subscriber %s exited with a message nacked when app ctx done", a.name),
167
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
168
                                        return
169
                                }
170
                        case <-ctx.Done():
171
                                return
172
                        case <-a.ctx.Done():
173
                                return
174
                        }
175
                }
176
        }, routine.AppName(a.appName))
177
        return msgCh, err
178
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

94
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
95
        var logger watermill.LoggerAdapter
96
        if utils.IsStrNotBlank(conf.Logger) {
97
                loggerType := inspect.TypeOf(conf.Logger)
98
                loggerValue := reflect.New(loggerType)
99
                if loggerValue.Type().Implements(customLoggerType) {
100
                        l := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
101
                        loggerValue.Interface().(customLogger).Init(l, opt.AppName, name)
102
                }
103
                logger = loggerValue.Convert(watermillLoggerType).Interface().(watermill.LoggerAdapter)
104
        }
105
106
        if conf.ConsumerConcurrency < 1 {
107
                conf.ConsumerConcurrency = 1
108
        }
109
110
        var (
111
                puber Publisher
112
                suber Subscriber
113
        )
114
        newFunc, ok := newFn[conf.Type]
115
        if ok {
116
                puber, suber = newFunc(ctx, opt.AppName, name, conf, logger)
117
        } else {
118
                panic(errors.Errorf("unknown message queue type: %+v", conf.Type))
119
        }
120
121
        locker.Lock()
122
        defer locker.Unlock()
123
        if suber != nil {
124
                if subscribers == nil {
125
                        subscribers = make(map[string]map[string]Subscriber)
126
                }
127
                if subscribers[opt.AppName] == nil {
128
                        subscribers[opt.AppName] = make(map[string]Subscriber)
129
                }
130
                if _, ok := subscribers[name]; ok {
131
                        panic(ErrDuplicatedSubscriberName)
132
                }
133
                subscribers[opt.AppName][name] = suber
134
135
                if routers == nil {
136
                        routers = make(map[string]map[string]IRouter)
137
                }
138
                if routers[opt.AppName] == nil {
139
                        routers[opt.AppName] = make(map[string]IRouter)
140
                }
141
                if _, ok := routers[opt.AppName][name]; ok {
142
                        panic(ErrDuplicatedRouterName)
143
                }
144
                routers[opt.AppName][name] = newRouter(ctx, opt.AppName, name, conf, puber, suber, logger)
145
146
                // ioc
147
                if opt.DI != nil {
148
                        opt.DI.
149
                                MustProvide(func() Subscriber { return sub(name, AppName(opt.AppName)) }, di.Name(name)).
150
                                MustProvide(func() IRouter { return Use(name, AppName(opt.AppName)) }, di.Name(name))
151
                }
152
153
        }
154
155
        if puber != nil {
156
                if publishers == nil {
157
                        publishers = make(map[string]map[string]Publisher)
158
                }
159
                if publishers[opt.AppName] == nil {
160
                        publishers[opt.AppName] = make(map[string]Publisher)
161
                }
162
                if _, ok := publishers[opt.AppName][name]; ok {
163
                        panic(ErrDuplicatedPublisherName)
164
                }
165
                publishers[opt.AppName][name] = puber
166
167
                // ioc
168
                if opt.DI != nil {
169
                        opt.DI.MustProvide(func() Publisher { return Pub(name, AppName(opt.AppName)) }, di.Name(name))
170
                }
171
        }
172
}
func router.isHandlerConflict
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

443
func (r *router) isHandlerConflict() (conflict bool) {
444
        if len(r.eventHandlers) == 0 {
445
                return
446
        }
447
        for name := range r.Handlers() {
448
                if !strings.Contains(name, defaultRouterEventHandlerName) {
449
                        return true
450
                }
451
        }
452
        return
453
}
func Sub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

216
func Sub(name string, opts ...utils.OptionExtender) Subscriber {
217
        opt := utils.ApplyOptions[useOption](opts...)
218
219
        locker.RLock()
220
        defer locker.RUnlock()
221
        subscribers, ok := subscribers[opt.appName]
222
        if !ok {
223
                panic(errors.Errorf("mq subscriber instance not found for app: %s", opt.appName))
224
        }
225
        subscriber, ok := subscribers[name]
226
        if !ok {
227
                panic(errors.Errorf("mq subscriber instance not found for name: %s", name))
228
        }
229
        return subscriber
230
}
func Pub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

200
func Pub(name string, opts ...utils.OptionExtender) Publisher {
201
        opt := utils.ApplyOptions[useOption](opts...)
202
203
        locker.RLock()
204
        defer locker.RUnlock()
205
        publishers, ok := publishers[opt.appName]
206
        if !ok {
207
                panic(errors.Errorf("mq publisher instance not found for app: %s", opt.appName))
208
        }
209
        publisher, ok := publishers[name]
210
        if !ok {
211
                panic(errors.Errorf("mq publisher instance not found for name: %s", name))
212
        }
213
        return publisher
214
}
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

232
func Use(name string, opts ...utils.OptionExtender) IRouter {
233
        opt := utils.ApplyOptions[useOption](opts...)
234
235
        locker.RLock()
236
        defer locker.RUnlock()
237
        routers, ok := routers[opt.appName]
238
        if !ok {
239
                panic(errors.Errorf("mq router instance not found for app: %s", opt.appName))
240
        }
241
        r, ok := routers[name]
242
        if !ok {
243
                panic(errors.Errorf("mq router instance not found for name: %s", name))
244
        }
245
        return r
246
}
func newRedisPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/redis.go:

38
func newRedisPublisher(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
39
        cli rdsDrv.UniversalClient) Publisher {
40
        cfg := millRds.PublisherConfig{
41
                Client:                cli,
42
                Marshaller:            millRds.DefaultMarshallerUnmarshaller{AppID: config.Use(appName).AppName()},
43
                Maxlens:               nil,
44
                DisableRedisConnClose: true,
45
        }
46
47
        pub, err := millRds.NewPublisher(cfg, logger)
48
        if err != nil {
49
                panic(errors.Wrapf(err, "initialize mq component redis publisher failed: %s", err))
50
        }
51
52
        return &redisPublisher{
53
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
54
                publisher:  pub,
55
        }
56
}
func newMysqlSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

71
func newMysqlSubscriber(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
72
        cli *sql.DB) Subscriber {
73
        cfg := millSql.SubscriberConfig{
74
                ConsumerGroup:  conf.ConsumerGroup,
75
                PollInterval:   0,
76
                ResendInterval: 0,
77
                RetryInterval:  0,
78
                BackoffManager: nil,
79
                SchemaAdapter: millSql.DefaultMySQLSchema{
80
                        GenerateMessagesTableName: func(topic string) string {
81
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
82
                        },
83
                        SubscribeBatchSize: conf.ConsumerConcurrency, // fetch how many rows per query
84
                },
85
                OffsetsAdapter: millSql.DefaultMySQLOffsetsAdapter{
86
                        GenerateMessagesOffsetsTableName: func(topic string) string {
87
                                return fmt.Sprintf("%s_offsets_%s", conf.MessageScheme, topic)
88
                        },
89
                },
90
                InitializeSchema:  true,
91
                DisablePersistent: !conf.Persistent,
92
        }
93
94
        sub, err := millSql.NewSubscriber(cli, cfg, logger)
95
        if err != nil {
96
                panic(errors.Wrapf(err, "initialize mq component mysql subscriber failed: %s", err))
97
        }
98
99
        return &mysqlSubscriber{
100
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
101
                subscriber: sub,
102
        }
103
}
func newPostgresPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

38
func newPostgresPublisher(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
39
        cli *sql.DB) Publisher {
40
        cfg := millSql.PublisherConfig{
41
                SchemaAdapter: millSql.DefaultPostgreSQLSchema{
42
                        GenerateMessagesTableName: func(topic string) string {
43
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
44
                        },
45
                        SubscribeBatchSize: conf.ConsumerConcurrency,
46
                },
47
                AutoInitializeSchema: true,
48
                AppID:                config.Use(appName).AppName(),
49
        }
50
51
        pub, err := millSql.NewPublisher(cli, cfg, logger)
52
        if err != nil {
53
                panic(errors.Wrapf(err, "initialize mq component postgres publisher failed: %s", err))
54
        }
55
56
        return &postgresPublisher{
57
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
58
                publisher:  pub,
59
        }
60
}
func newKafkaPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

35
func newKafkaPublisher(ctx context.Context, appName, name string,
36
        conf *Conf, logger watermill.LoggerAdapter) Publisher {
37
        cfg := kafka.PublisherConfig{
38
                Brokers:               conf.Endpoint.Addresses,
39
                Marshaler:             kafka.DefaultMarshaler{AppID: config.Use(appName).AppName()},
40
                OverwriteSaramaConfig: parseKafkaConf(appName, conf),
41
        }
42
43
        pub, err := kafka.NewPublisher(cfg, logger)
44
        if err != nil {
45
                panic(errors.Wrapf(err, "initialize mq component kafka publisher failed: %s", err))
46
        }
47
48
        return &kafkaPublisher{
49
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
50
                publisher:  pub,
51
        }
52
}
func router.Start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

187
func (r *router) Start() {
188
        if r.isHandlerConflict() {
189
                panic(ErrEventHandlerConflict)
190
        }
191
        if len(r.eventHandlers) > 0 {
192
                r.runEventHandlers()
193
        }
194
        routine.Go(r.run, routine.AppName(r.appName))
195
}
func newRedisSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/redis.go:

67
func newRedisSubscriber(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
68
        cli rdsDrv.UniversalClient) Subscriber {
69
        cfg := millRds.SubscriberConfig{
70
                Client:                    cli,
71
                Unmarshaller:              millRds.DefaultMarshallerUnmarshaller{AppID: config.Use(appName).AppName()},
72
                Consumer:                  "",
73
                ConsumerGroup:             conf.ConsumerGroup,
74
                NackResendSleep:           0,
75
                BlockTime:                 0,
76
                ClaimInterval:             0,
77
                ClaimBatchSize:            0,
78
                MaxIdleTime:               0,
79
                CheckConsumersInterval:    0,
80
                ConsumerTimeout:           0,
81
                OldestId:                  "",
82
                ShouldClaimPendingMessage: nil,
83
                DisableRedisConnClose:     true,
84
        }
85
86
        sub, err := millRds.NewSubscriber(cfg, logger)
87
        if err != nil {
88
                panic(errors.Wrapf(err, "initialize mq component redis subscriber failed: %s", err))
89
        }
90
91
        return &redisSubscriber{
92
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
93
                subscriber: sub,
94
        }
95
}
func newMysqlPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mysql.go:

38
func newMysqlPublisher(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
39
        cli *sql.DB) Publisher {
40
        cfg := millSql.PublisherConfig{
41
                SchemaAdapter: millSql.DefaultMySQLSchema{
42
                        GenerateMessagesTableName: func(topic string) string {
43
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
44
                        },
45
                        SubscribeBatchSize: 1,
46
                },
47
                AutoInitializeSchema: true,
48
                AppID:                config.Use(appName).AppName(),
49
        }
50
51
        pub, err := millSql.NewPublisher(cli, cfg, logger)
52
        if err != nil {
53
                panic(errors.Wrapf(err, "initialize mq component mysql publisher failed: %s", err))
54
        }
55
56
        return &mysqlPublisher{
57
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
58
                publisher:  pub,
59
        }
60
}
func newPostgresSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/postgres.go:

71
func newPostgresSubscriber(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter,
72
        cli *sql.DB) Subscriber {
73
        cfg := millSql.SubscriberConfig{
74
                ConsumerGroup:  conf.ConsumerGroup,
75
                PollInterval:   0,
76
                ResendInterval: 0,
77
                RetryInterval:  0,
78
                BackoffManager: nil,
79
                SchemaAdapter: millSql.DefaultPostgreSQLSchema{
80
                        GenerateMessagesTableName: func(topic string) string {
81
                                return fmt.Sprintf("%s_%s", conf.MessageScheme, topic)
82
                        },
83
                        SubscribeBatchSize: conf.ConsumerConcurrency, // fetch how many rows per query
84
                },
85
                OffsetsAdapter: millSql.DefaultPostgreSQLOffsetsAdapter{
86
                        GenerateMessagesOffsetsTableName: func(topic string) string {
87
                                return fmt.Sprintf("%s_offsets_%s", conf.MessageScheme, topic)
88
                        },
89
                },
90
                InitializeSchema:  true,
91
                DisablePersistent: !conf.Persistent,
92
        }
93
94
        sub, err := millSql.NewSubscriber(cli, cfg, logger)
95
        if err != nil {
96
                panic(errors.Wrapf(err, "initialize mq component mysql subscriber failed: %s", err))
97
        }
98
99
        return &postgresSubscriber{
100
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
101
                subscriber: sub,
102
        }
103
}
func newAMQPPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

34
func newAMQPPublisher(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) Publisher {
35
        ep := parseAMQPEndpoint(conf)
36
37
        var genFunc amqp.QueueNameGenerator
38
        if utils.IsStrNotBlank(conf.ConsumerGroup) {
39
                genFunc = amqp.GenerateQueueNameTopicNameWithSuffix(conf.ConsumerGroup)
40
        } else {
41
                genFunc = amqp.GenerateQueueNameTopicName
42
        }
43
44
        var cfg amqp.Config
45
        if conf.Persistent {
46
                cfg = amqp.NewDurablePubSubConfig(ep, genFunc)
47
        } else {
48
                cfg = amqp.NewNonDurablePubSubConfig(ep, genFunc)
49
        }
50
51
        cfg.Marshaler = amqp.DefaultMarshaler{
52
                NotPersistentDeliveryMode: !conf.Persistent,
53
                AppID:                     config.Use(appName).AppName(),
54
        }
55
56
        pub, err := amqp.NewPublisher(cfg, logger)
57
        if err != nil {
58
                panic(errors.Wrapf(err, "initialize mq component amqp publisher failed: %s", err))
59
        }
60
61
        return &_AMQPPublisher{
62
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
63
                publisher:  pub,
64
        }
65
}
func newAMQPSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

76
func newAMQPSubscriber(ctx context.Context, appName, name string, conf *Conf, logger watermill.LoggerAdapter) Subscriber {
77
        ep := parseAMQPEndpoint(conf)
78
79
        var genFunc amqp.QueueNameGenerator
80
        if utils.IsStrNotBlank(conf.ConsumerGroup) {
81
                genFunc = amqp.GenerateQueueNameTopicNameWithSuffix(conf.ConsumerGroup)
82
        } else {
83
                genFunc = amqp.GenerateQueueNameTopicName
84
        }
85
86
        var cfg amqp.Config
87
        if conf.Persistent {
88
                cfg = amqp.NewDurablePubSubConfig(ep, genFunc)
89
        } else {
90
                cfg = amqp.NewNonDurablePubSubConfig(ep, genFunc)
91
        }
92
93
        sub, err := amqp.NewSubscriber(cfg, logger)
94
        if err != nil {
95
                panic(errors.Wrapf(err, "initialize mq component amqp subscriber failed: %s", err))
96
        }
97
98
        utils.MustSuccess(sub.SubscribeInitialize(conf.Topic))
99
100
        return &_AMQPSubscriber{
101
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
102
                subscriber: sub,
103
        }
104
}
func newRouter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

59
func newRouter(ctx context.Context, appName, name string, conf *Conf,
60
        pub Publisher, sub Subscriber, logger watermill.LoggerAdapter) *router {
61
        r := utils.Must(mw.NewRouter(mw.RouterConfig{CloseTimeout: 15 * time.Second}, logger))
62
        r.AddPlugin(plugin.SignalsHandler)
63
        r.AddMiddleware(
64
                middleware.Recoverer,
65
                middleware.CorrelationID,
66
        )
67
        for _, mwsConf := range conf.ConsumeMiddlewares {
68
                switch mwsConf.Type {
69
                case middlewareTypeRetry:
70
                        r.AddMiddleware(middleware.Retry{
71
                                MaxRetries:          mwsConf.RetryMaxRetries,
72
                                InitialInterval:     utils.Must(time.ParseDuration(mwsConf.RetryInitialInterval)),
73
                                MaxInterval:         utils.Must(time.ParseDuration(mwsConf.RetryMaxInterval)),
74
                                Multiplier:          mwsConf.RetryMultiplier,
75
                                MaxElapsedTime:      utils.Must(time.ParseDuration(mwsConf.RetryMaxElapsedTime)),
76
                                RandomizationFactor: mwsConf.RetryRandomizationFactor,
77
                                OnRetryHook: func(attempt int, delay time.Duration) {
78
                                        logTrace(ctx, logger, appName, name,
79
                                                "retry to consume message [attempt[%v] delay[%s]]", attempt, delay)
80
                                },
81
                                Logger: logger,
82
                        }.Middleware)
83
                case middlewareTypeThrottle:
84
                        r.AddMiddleware(
85
                                middleware.NewThrottle(
86
                                        int64(mwsConf.ThrottleCount),
87
                                        utils.Must(time.ParseDuration(mwsConf.ThrottleDuration)),
88
                                ).Middleware,
89
                        )
90
                case middlewareTypeInstanceAck:
91
                        r.AddMiddleware(middleware.InstantAck)
92
                case middlewareTypePoison:
93
                        shouldGoToPoisonQueue := func(err error) bool { return err != nil }
94
                        r.AddMiddleware(
95
                                utils.Must(middleware.PoisonQueueWithFilter(
96
                                        pub.watermillPublisher(),
97
                                        mwsConf.PoisonTopic,
98
                                        shouldGoToPoisonQueue,
99
                                )),
100
                        )
101
                case middlewareTypeTimeout:
102
                        r.AddMiddleware(middleware.Timeout(utils.Must(time.ParseDuration(mwsConf.Timeout))))
103
                case middlewareTypeCircuitBreaker:
104
                        var expr gval.Evaluable
105
                        if utils.IsStrNotBlank(mwsConf.CircuitBreakerTripExpr) {
106
                                expr = utils.Must(gval.Full().NewEvaluable(mwsConf.CircuitBreakerTripExpr))
107
                        }
108
                        r.AddMiddleware(middleware.NewCircuitBreaker(gobreaker.Settings{
109
                                Name:        name,
110
                                MaxRequests: uint32(mwsConf.CircuitBreakerMaxRequests),
111
                                Interval:    utils.Must(time.ParseDuration(mwsConf.CircuitBreakerInterval)),
112
                                Timeout:     utils.Must(time.ParseDuration(mwsConf.CircuitBreakerTimeout)),
113
                                ReadyToTrip: func(counts gobreaker.Counts) bool {
114
                                        // fallback to default ready to trip expression
115
                                        if expr == nil {
116
                                                return counts.ConsecutiveFailures > 5
117
                                        }
118
                                        if ok, err := expr.EvalBool(ctx, map[string]uint32{
119
                                                "requests":              counts.Requests,
120
                                                "total_successes":       counts.TotalSuccesses,
121
                                                "total_failures":        counts.TotalFailures,
122
                                                "consecutive_successes": counts.ConsecutiveSuccesses,
123
                                                "consecutive_failures":  counts.ConsecutiveFailures,
124
                                        }); err == nil {
125
                                                return ok
126
                                        }
127
                                        // fallback to default ready to trip expression
128
                                        return counts.ConsecutiveFailures > 5
129
                                },
130
                                OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
131
                                        logInfo(ctx, logger, appName, name, "circuit breaker state changed: %s -> %s", from, to)
132
                                },
133
                                IsSuccessful: func(err error) bool { return err == nil },
134
                        }).Middleware)
135
                default:
136
                        typ := inspect.TypeOf(string(mwsConf.Type))
137
                        if typ == nil || typ.ConvertibleTo(watermillHandlerMiddlewareType) {
138
                                panic(errors.Errorf("unknown mq middleware: %s", mwsConf.Type))
139
                        }
140
                        mws := reflect.New(typ).Elem().Convert(watermillHandlerMiddlewareType).Interface()
141
                        r.AddMiddleware(mws.(mw.HandlerMiddleware))
142
                }
143
        }
144
145
        rr := &router{
146
                ctx:                     ctx,
147
                appName:                 appName,
148
                c:                       conf,
149
                pub:                     pub,
150
                sub:                     sub,
151
                Router:                  r,
152
                eventHandlers:           make(map[string]*handler),
153
                eventSubscriberHandlers: make(map[string]*handler),
154
        }
155
        rr.serializeType = serialize.ParseAlgorithm(conf.SerializeType)
156
        rr.compressType = compress.ParseAlgorithm(conf.CompressType)
157
158
        return rr
159
}
func newPulsarPublisher
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/pulsar.go:

36
func newPulsarPublisher(ctx context.Context, appName, name string,
37
        conf *Conf, logger watermill.LoggerAdapter) Publisher {
38
        cfg := pulsar.PublisherConfig{
39
                URL:   fmt.Sprintf("pulsar://%s", strings.TrimPrefix(conf.Endpoint.Addresses[0], "pulsar://")),
40
                AppID: config.Use(appName).AppName(),
41
        }
42
        hasUser := utils.IsStrNotBlank(conf.Endpoint.User)
43
        hasPassword := utils.IsStrNotBlank(conf.Endpoint.Password)
44
        hasAuthType := utils.IsStrNotBlank(conf.Endpoint.AuthType)
45
        if hasUser && hasPassword {
46
                cfg.Authentication = utils.Must(plsDrv.NewAuthenticationBasic(conf.Endpoint.User, conf.Endpoint.Password))
47
        }
48
        if hasAuthType {
49
                cfg.Authentication = utils.Must(plsDrv.NewAuthentication(conf.Endpoint.AuthType, conf.Endpoint.Password))
50
        }
51
52
        pub, err := pulsar.NewPublisher(cfg, logger)
53
        if err != nil {
54
                panic(errors.Wrapf(err, "initialize mq component pulsar publisher failed: %s", err))
55
        }
56
57
        return &pulsarPublisher{
58
                abstractMQ: newPub(ctx, pub, appName, name, conf, logger),
59
                publisher:  pub,
60
        }
61
}
func abstractMQ.PublishRaw
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

99
func (a *abstractMQ) PublishRaw(ctx context.Context, opts ...utils.OptionExtender) (err error) {
100
        opt := utils.ApplyOptions[pubOption](opts...)
101
        msgs := opt.watermillMessages
102
        for _, msg := range opt.messages {
103
                wmsg := mw.NewMessage(msg.ID(), msg.Payload())
104
                wmsg.Metadata = fusCtx.WatermillMetadata(ctx)
105
                wmsg.SetContext(ctx)
106
                msgs = append(msgs, wmsg)
107
        }
108
        if len(msgs) == 0 {
109
                logInfo(ctx, a.logger, a.appName, a.name, "none messages to publish")
110
                return
111
        }
112
113
        if !opt.async {
114
                return a.pub.Publish(ctx, a.conf.Topic, msgs...)
115
        }
116
117
        routine.Goc(ctx, func() {
118
                idList := utils.SliceMapping(msgs, func(s *mw.Message) (id string) { return s.UUID })
119
                idList = utils.NewSet(idList...).Items()
120
                retryFunc := func(attempt uint) error {
121
                        if attempt > 1 {
122
                                logInfo(ctx, a.logger, a.appName, a.name,
123
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
124
                                        a.conf.Topic, idList, len(msgs), attempt-1)
125
                        }
126
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
127
                }
128
129
                if err = retry.Retry(retryFunc, opt.asyncStrategies...); err != nil {
130
                        logError(ctx, a.logger, a.appName, a.name,
131
                                "retry to publish topic message failed [err[%s] topic[%s] message%v[%v]]",
132
                                err, a.conf.Topic, idList, len(msgs))
133
                }
134
        }, routine.AppName(a.appName))
135
        return
136
}
func newKafkaSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

63
func newKafkaSubscriber(ctx context.Context, appName, name string,
64
        conf *Conf, logger watermill.LoggerAdapter) Subscriber {
65
        cfg := kafka.SubscriberConfig{
66
                Brokers:               conf.Endpoint.Addresses,
67
                Unmarshaler:           kafka.DefaultMarshaler{AppID: config.Use(appName).AppName()},
68
                OverwriteSaramaConfig: parseKafkaConf(appName, conf),
69
                ConsumerGroup:         conf.ConsumerGroup,
70
                NackResendSleep:       100 * time.Millisecond,
71
                ReconnectRetrySleep:   time.Second,
72
                InitializeTopicDetails: &sarama.TopicDetail{
73
                        NumPartitions:     -1,
74
                        ReplicationFactor: -1,
75
                        ReplicaAssignment: nil,
76
                        ConfigEntries:     nil,
77
                },
78
        }
79
80
        sub, err := kafka.NewSubscriber(cfg, logger)
81
        if err != nil {
82
                panic(errors.Wrapf(err, "initialize mq component kafka subscriber failed: %s", err))
83
        }
84
85
        if err = sub.SubscribeInitialize(conf.Topic); err != nil {
86
                panic(errors.Wrapf(err, "initialize mq component kafka subscriber intialize: %s", err))
87
        }
88
89
        return &kafkaSubscriber{
90
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
91
                subscriber: sub,
92
        }
93
}
func abstractMQ.newObjectMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

258
func (a *abstractMQ) newObjectMessage(ctx context.Context, object any, opt *pubOption) (
259
        msg *mw.Message, err error) {
260
        payload, err := pd.Seal(object, pd.Compress(a.compressType), pd.Serialize(a.serializeType))
261
        if err != nil {
262
                return
263
        }
264
        uuid := utils.ULID()
265
        if opt.objectUUIDGenFunc.IsValid() && opt.objectUUIDGenFunc.Kind() == reflect.Func {
266
                inType := opt.objectUUIDGenFunc.Type().In(0)
267
                inParam := reflect.ValueOf(object).Convert(inType)
268
                uuid = opt.objectUUIDGenFunc.Call([]reflect.Value{inParam})[0].Interface().(string)
269
        }
270
        msg = mw.NewMessage(uuid, payload)
271
        msg.Metadata = fusCtx.WatermillMetadata(ctx)
272
        msg.SetContext(ctx)
273
        return
274
}
func router.run
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

201
func (r *router) run() (err error) {
202
        if r.Router.IsRunning() {
203
                return r.Router.RunHandlers(r.ctx)
204
        }
205
        if err = r.Router.Run(r.ctx); err != nil {
206
                if errors.Is(err, mw.ErrRouterIsAlreadyRunning) {
207
                        return r.Router.RunHandlers(r.ctx)
208
                }
209
        }
210
        return
211
}
func event[T].Ack
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

230
func (e *event[T]) Ack() bool {
231
        if e.ackfn != nil {
232
                return e.ackfn()
233
        }
234
        return true
235
}
func parseKafkaConf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

99
func parseKafkaConf(appName string, conf *Conf) (saramaCfg *sarama.Config) {
100
        saramaCfg = sarama.NewConfig()
101
        saramaCfg.Producer.Return.Errors = true
102
        saramaCfg.Producer.Return.Successes = true
103
        saramaCfg.Producer.RequiredAcks = sarama.WaitForLocal
104
        saramaCfg.Producer.Retry.Max = 10
105
        saramaCfg.Consumer.Fetch.Default = 16 * 1024 * 1024 // 16mb, default is 1mb
106
        saramaCfg.Consumer.Offsets.Initial = sarama.OffsetNewest
107
        saramaCfg.Consumer.Offsets.AutoCommit.Enable = true
108
        saramaCfg.Consumer.Offsets.AutoCommit.Interval = time.Second // only work when auto commit disabled
109
        saramaCfg.Consumer.Return.Errors = true
110
        saramaCfg.Metadata.Retry.Backoff = time.Second * 2
111
        saramaCfg.ClientID = config.Use(appName).AppName()
112
        if utils.IsStrNotBlank(conf.Endpoint.Version) {
113
                saramaCfg.Version = utils.Must(sarama.ParseKafkaVersion(conf.Endpoint.Version))
114
        }
115
        if utils.IsStrNotBlank(conf.Endpoint.User) {
116
                saramaCfg.Net.SASL.Enable = true
117
                saramaCfg.Net.SASL.User = conf.Endpoint.User
118
                saramaCfg.Net.SASL.Password = conf.Endpoint.Password
119
                saramaCfg.Net.SASL.Mechanism = sarama.SASLTypePlaintext
120
                switch {
121
                case strings.EqualFold(conf.Endpoint.AuthType, sarama.SASLTypeSCRAMSHA256):
122
                        saramaCfg.Net.SASL.Mechanism = sarama.SASLTypeSCRAMSHA256
123
                case strings.EqualFold(conf.Endpoint.AuthType, sarama.SASLTypeSCRAMSHA512):
124
                        saramaCfg.Net.SASL.Mechanism = sarama.SASLTypeSCRAMSHA512
125
                case strings.EqualFold(conf.Endpoint.AuthType, sarama.SASLTypeOAuth):
126
                        saramaCfg.Net.SASL.Mechanism = sarama.SASLTypeOAuth
127
                        saramaCfg.Net.SASL.TokenProvider = &kafkaOAuthProvider{token: saramaCfg.Net.SASL.Password}
128
                }
129
        }
130
        return
131
}
func messageConvertFrom
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

285
func messageConvertFrom(src *mw.Message,
286
        serializeType serialize.Algorithm, compressType compress.Algorithm) (dst Message, err error) {
287
        _, data, isRaw, err := pd.UnsealRaw(src.Payload, pd.Compress(compressType))
288
        if err != nil {
289
                return
290
        }
291
        src.SetContext(fusCtx.New(fusCtx.Watermill(src.Metadata)))
292
        msg := &message{Message: src, payload: data}
293
        if !isRaw {
294
                _, msg.obj, _, err = pd.Unseal(src.Payload,
295
                        pd.Serialize(serializeType), pd.Compress(compressType))
296
                if err != nil {
297
                        return
298
                }
299
        }
300
        dst = msg
301
        return
302
}
func newPulsarSubscriber
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/pulsar.go:

72
func newPulsarSubscriber(ctx context.Context, appName, name string,
73
        conf *Conf, logger watermill.LoggerAdapter) Subscriber {
74
        cfg := &pulsar.SubscriberConfig{
75
                URL:        fmt.Sprintf("pulsar://%s", strings.TrimPrefix(conf.Endpoint.Addresses[0], "pulsar://")),
76
                QueueGroup: conf.ConsumerGroup,
77
                Persistent: conf.Persistent,
78
        }
79
        hasUser := utils.IsStrNotBlank(conf.Endpoint.User)
80
        hasPassword := utils.IsStrNotBlank(conf.Endpoint.Password)
81
        hasAuthType := utils.IsStrNotBlank(conf.Endpoint.AuthType)
82
        if hasUser && hasPassword {
83
                cfg.Authentication = utils.Must(plsDrv.NewAuthenticationBasic(conf.Endpoint.User, conf.Endpoint.Password))
84
        }
85
        if hasAuthType {
86
                params := conf.Endpoint.Password
87
                switch conf.Endpoint.AuthType {
88
                case "basic", "org.apache.pulsar.client.impl.auth.AuthenticationBasic":
89
                        params = utils.MustJsonMarshalString(map[string]string{
90
                                "username": conf.Endpoint.User,
91
                                "password": conf.Endpoint.Password,
92
                        })
93
                }
94
                cfg.Authentication = utils.Must(plsDrv.NewAuthentication(conf.Endpoint.AuthType, params))
95
        }
96
97
        sub, err := pulsar.NewSubscriber(cfg, logger)
98
        if err != nil {
99
                panic(errors.Wrapf(err, "initialize mq component pulsar subscriber failed: %s", err))
100
        }
101
102
        return &pulsarSubscriber{
103
                abstractMQ: newSub(ctx, sub, appName, name, conf, logger),
104
                subscriber: sub,
105
        }
106
}
func parseAMQPEndpoint
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/amqp.go:

110
func parseAMQPEndpoint(conf *Conf) (result string) {
111
        hasUser := utils.IsStrNotBlank(conf.Endpoint.User)
112
        hasPassword := utils.IsStrNotBlank(conf.Endpoint.Password)
113
        if hasUser && hasPassword {
114
                addr := strings.TrimPrefix(conf.Endpoint.Addresses[0], "amqp://")
115
                result = fmt.Sprintf("amqp://%s:%s@%s", conf.Endpoint.User, conf.Endpoint.Password, addr)
116
        } else if hasUser {
117
                addr := strings.TrimPrefix(conf.Endpoint.Addresses[0], "amqp://")
118
                result = fmt.Sprintf("amqp://%s@%s", conf.Endpoint.User, addr)
119
        } else {
120
                addr := strings.TrimPrefix(conf.Endpoint.Addresses[0], "amqp://")
121
                result = fmt.Sprintf("amqp://%s", addr)
122
        }
123
124
        return
125
}
func @146:13
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

146
func() {
147
                defer close(msgCh)
148
                for {
149
                        select {
150
                        case wmsg, ok := <-ch:
151
                                if !ok {
152
                                        return
153
                                }
154
                                msg := rawMessageConvertFrom(wmsg)
155
                                select {
156
                                case msgCh <- msg:
157
                                case <-ctx.Done():
158
                                        msg.Nack()
159
                                        a.logger.Info(fmt.Sprintf(
160
                                                "raw subscriber %s exited with a message nacked when business ctx done", a.name),
161
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
162
                                        return
163
                                case <-a.ctx.Done():
164
                                        msg.Nack()
165
                                        a.logger.Info(fmt.Sprintf(
166
                                                "raw subscriber %s exited with a message nacked when app ctx done", a.name),
167
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
168
                                        return
169
                                }
170
                        case <-ctx.Done():
171
                                return
172
                        case <-a.ctx.Done():
173
                                return
174
                        }
175
                }
176
        }
func router.addHandler
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

213
func (r *router) addHandler(handlerName, consumerName string, hdr any, opt *routerOption) {
214
        switch fn := hdr.(type) {
215
        case HandlerFunc:
216
                r.Router.AddNoPublisherHandler(
217
                        consumerName,
218
                        r.sub.topic(),
219
                        r.sub.watermillSubscriber(),
220
                        func(wmsg *mw.Message) (err error) {
221
                                msg, err := messageConvertFrom(wmsg, r.serializeType, r.compressType)
222
                                if err != nil {
223
                                        return
224
                                }
225
                                return fn(msg)
226
                        },
227
                )
228
        case mw.NoPublishHandlerFunc:
229
                r.Router.AddNoPublisherHandler(
230
                        consumerName,
231
                        r.sub.topic(),
232
                        r.sub.watermillSubscriber(),
233
                        fn,
234
                )
235
        case mw.HandlerFunc:
236
                r.Router.AddHandler(
237
                        consumerName,
238
                        r.sub.topic(),
239
                        r.sub.watermillSubscriber(),
240
                        r.pub.topic(),
241
                        r.pub.watermillPublisher(),
242
                        fn,
243
                )
244
        default:
245
                fnVal := reflect.ValueOf(hdr)
246
                switch {
247
                case fnVal.CanConvert(watermillHandlerFuncType):
248
                        r.Router.AddNoPublisherHandler(
249
                                consumerName,
250
                                r.sub.topic(),
251
                                r.sub.watermillSubscriber(),
252
                                func(msg *mw.Message) error {
253
                                        rets := fnVal.Convert(watermillHandlerFuncType).Call(
254
                                                []reflect.Value{reflect.ValueOf(rawMessageConvertFrom(msg))},
255
                                        )
256
                                        return utils.ParseVariadicFuncResult[error](rets, 0)
257
                                },
258
                        )
259
                case fnVal.CanConvert(watermillNoPublishHandlerFuncType):
260
                        r.Router.AddNoPublisherHandler(
261
                                consumerName,
262
                                r.sub.topic(),
263
                                r.sub.watermillSubscriber(),
264
                                func(msg *mw.Message) error {
265
                                        rets := fnVal.
266
                                                Convert(watermillNoPublishHandlerFuncType).
267
                                                Call([]reflect.Value{reflect.ValueOf(msg)})
268
                                        return utils.ParseVariadicFuncResult[error](rets, 0)
269
                                },
270
                        )
271
                case fnVal.CanConvert(handlerFuncType):
272
                        r.Router.AddHandler(
273
                                consumerName,
274
                                r.sub.topic(),
275
                                r.sub.watermillSubscriber(),
276
                                r.pub.topic(),
277
                                r.pub.watermillPublisher(),
278
                                func(wmsg *mw.Message) (msgs []*mw.Message, err error) {
279
                                        msg, err := messageConvertFrom(wmsg, r.serializeType, r.compressType)
280
                                        if err != nil {
281
                                                return
282
                                        }
283
                                        rets := fnVal.Convert(handlerFuncType).Call([]reflect.Value{reflect.ValueOf(msg)})
284
                                        msgs = utils.ParseVariadicFuncResult[[]*mw.Message](rets, 0)
285
                                        err = utils.ParseVariadicFuncResult[error](rets, 0)
286
                                        return
287
                                },
288
                        )
289
                case isEventHandler(fnVal):
290
                        r.handleEvent(handlerName, fnVal, opt)
291
                default:
292
                        r.Router.AddNoPublisherHandler(
293
                                consumerName,
294
                                r.sub.topic(),
295
                                r.sub.watermillSubscriber(),
296
                                r.handle(hdr),
297
                        )
298
                }
299
        }
300
}
func abstractMQ.Publish
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

52
func (a *abstractMQ) Publish(ctx context.Context, opts ...utils.OptionExtender) (err error) {
53
        opt := utils.ApplyOptions[pubOption](opts...)
54
        msgs := opt.watermillMessages
55
        for _, msg := range opt.messages {
56
                msg, err := a.newMessage(ctx, msg, opt)
57
                if err != nil {
58
                        return err
59
                }
60
                msgs = append(msgs, msg)
61
        }
62
        for _, object := range opt.objects {
63
                msg, err := a.newObjectMessage(ctx, object, opt)
64
                if err != nil {
65
                        return err
66
                }
67
                msgs = append(msgs, msg)
68
        }
69
        if len(msgs) == 0 {
70
                logInfo(ctx, a.logger, a.appName, a.name, "none messages to publish")
71
                return
72
        }
73
74
        if !opt.async {
75
                return a.pub.Publish(ctx, a.conf.Topic, msgs...)
76
        }
77
78
        routine.Goc(ctx, func() {
79
                idList := utils.SliceMapping(msgs, func(s *mw.Message) (id string) { return s.UUID })
80
                idList = utils.NewSet(idList...).Items()
81
                retryFunc := func(attempt uint) error {
82
                        if attempt > 1 {
83
                                logInfo(ctx, a.logger, a.appName, a.name,
84
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
85
                                        a.conf.Topic, idList, len(msgs), attempt-1)
86
                        }
87
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
88
                }
89
90
                if err = retry.Retry(retryFunc, opt.asyncStrategies...); err != nil {
91
                        logError(ctx, a.logger, a.appName, a.name,
92
                                "retry to publish topic message failed [err[%s] topic[%s] message%v[%v]]",
93
                                err, a.conf.Topic, idList, len(msgs))
94
                }
95
        }, routine.AppName(a.appName))
96
        return
97
}
func @129:26
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

129
func(ctx context.Context, event Event[T]) (msgs []Message, err error) {
130
                        select {
131
                        case out <- event:
132
                        case <-r.Router.ClosingInProgressCh:
133
                                event.Nack()
134
                                e.logger.Info(fmt.Sprintf("event subscriber %s exited", e.name), nil)
135
                                return
136
                        case <-ctx.Done():
137
                                event.Nack()
138
                                e.logger.Info(fmt.Sprintf(
139
                                        "event subscriber %s exited with a message nacked when business ctx done", e.name),
140
                                        watermill.LogFields{watermill.ContextLogFieldKey: ctx})
141
                                return
142
                        case <-e.ctx.Done():
143
                                event.Nack()
144
                                e.logger.Info(fmt.Sprintf(
145
                                        "event subscriber %s exited with a message nacked when app ctx done", e.name),
146
                                        watermill.LogFields{watermill.ContextLogFieldKey: ctx})
147
                                return
148
                        }
149
150
                        msgs = append(msgs,
151
                                &message{Message: &mw.Message{Metadata: mw.Metadata{watermill.MessageRouterAck: ""}}})
152
                        return
153
                }
func @188:13
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

188
func() {
189
                defer close(msgCh)
190
                for {
191
                        select {
192
                        case wmsg, ok := <-ch:
193
                                if !ok {
194
                                        return
195
                                }
196
                                _, data, isRaw, err := pd.UnsealRaw(wmsg.Payload, pd.Compress(a.compressType))
197
                                if err != nil {
198
                                        a.logger.Error("unseal message failed", err, watermill.LogFields{
199
                                                watermill.ContextLogFieldKey: ctx,
200
                                        })
201
                                        continue
202
                                }
203
                                wmsg.SetContext(fusCtx.New(fusCtx.Watermill(wmsg.Metadata)))
204
                                msg := &message{Message: wmsg, payload: data}
205
                                if !isRaw {
206
                                        _, msg.obj, _, err = pd.Unseal(wmsg.Payload,
207
                                                pd.Serialize(a.serializeType), pd.Compress(a.compressType))
208
                                        if err != nil {
209
                                                a.logger.Error("unseal message object failed", err, watermill.LogFields{
210
                                                        watermill.ContextLogFieldKey: ctx,
211
                                                })
212
                                                continue
213
                                        }
214
                                }
215
                                select {
216
                                case msgCh <- msg:
217
                                case <-ctx.Done():
218
                                        msg.Nack()
219
                                        a.logger.Info(fmt.Sprintf(
220
                                                "subscriber %s exited with a message nacked when business ctx done", a.name),
221
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
222
                                        return
223
                                case <-a.ctx.Done():
224
                                        msg.Nack()
225
                                        a.logger.Info(fmt.Sprintf(
226
                                                "subscriber %s exited with a message nacked when app ctx done", a.name),
227
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
228
                                        return
229
                                }
230
231
                        case <-ctx.Done():
232
                                return
233
                        case <-a.ctx.Done():
234
                                return
235
                        }
236
                }
237
        }
func setParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/utils.go:

29
func setParams(typ reflect.Type, embed bool, params ...any) (arg any) {
30
        if typ == nil {
31
                return
32
        }
33
34
        argValPtr := reflect.New(typ)
35
        argVal := argValPtr.Elem()
36
        if !embed {
37
                if len(params) > 0 {
38
                        argVal.Set(reflect.ValueOf(params[0]))
39
                }
40
                return argValPtr.Interface()
41
        }
42
43
        for i := 0; i < len(params); i++ {
44
                ft := argVal.Field(i)
45
                ft.Set(reflect.ValueOf(params[i]).Convert(ft.Type()))
46
        }
47
        return argValPtr.Interface()
48
}
func formatFields
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

28
func formatFields(ctx context.Context) (fs watermill.LogFields) {
29
        fs = make(watermill.LogFields, 4)
30
        if userID := fusCtx.GetUserID(ctx); utils.IsStrNotBlank(userID) {
31
                fs["user_id"] = userID
32
        }
33
        if traceID := fusCtx.GetTraceID(ctx); utils.IsStrNotBlank(traceID) {
34
                fs["trace_id"] = traceID
35
        }
36
        if taskID := fusCtx.GetCronTaskID(ctx); utils.IsStrNotBlank(taskID) {
37
                fs["cron_task_id"] = taskID
38
        }
39
        if taskName := fusCtx.GetCronTaskName(ctx); utils.IsStrNotBlank(taskName) {
40
                fs["cron_task_name"] = taskName
41
        }
42
        return
43
}
func sub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

184
func sub(name string, opts ...utils.OptionExtender) Subscriber {
185
        opt := utils.ApplyOptions[useOption](opts...)
186
187
        locker.RLock()
188
        defer locker.RUnlock()
189
        subscribers, ok := subscribers[opt.appName]
190
        if !ok {
191
                panic(errors.Errorf("mq subscriber instance not found for app: %s", opt.appName))
192
        }
193
        subscriber, ok := subscribers[name]
194
        if !ok {
195
                panic(errors.Errorf("mq subscriber instance not found for name: %s", name))
196
        }
197
        return subscriber
198
}
func router.Serve
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

173
func (r *router) Serve() (err error) {
174
        if r.isHandlerConflict() {
175
                panic(ErrEventHandlerConflict)
176
        }
177
        if len(r.eventHandlers) > 0 {
178
                r.runEventHandlers()
179
        }
180
        if err = r.run(); err != nil {
181
                return
182
        }
183
        <-r.Router.ClosedCh
184
        return
185
}
func wrapParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/utils.go:

7
func wrapParams(fn any) (argType reflect.Type) {
8
        typ := reflect.TypeOf(fn)
9
10
        inLength := typ.NumIn()
11
        if inLength == 1 {
12
                return
13
        }
14
        if inLength >= 2 {
15
                return typ.In(1)
16
        }
17
18
        return
19
}
func abstractMQ.newMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

247
func (a *abstractMQ) newMessage(ctx context.Context, src Message, _ *pubOption) (
248
        msg *mw.Message, err error) {
249
        payload, err := pd.Seal(src.Payload(), pd.Compress(a.compressType))
250
        if err != nil {
251
                return
252
        }
253
        msg = mw.NewMessage(src.ID(), payload)
254
        msg.Metadata = fusCtx.WatermillMetadata(ctx)
255
        msg.SetContext(ctx)
256
        return
257
}
func abstractMQ.Subscribe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

180
func (a *abstractMQ) Subscribe(ctx context.Context, opts ...utils.OptionExtender) (dst <-chan Message, err error) {
181
        opt := utils.ApplyOptions[subOption](opts...)
182
        ch, err := a.sub.Subscribe(ctx, a.conf.Topic)
183
        if err != nil {
184
                return
185
        }
186
187
        msgCh := make(chan Message, opt.channelLength)
188
        routine.Go(func() {
189
                defer close(msgCh)
190
                for {
191
                        select {
192
                        case wmsg, ok := <-ch:
193
                                if !ok {
194
                                        return
195
                                }
196
                                _, data, isRaw, err := pd.UnsealRaw(wmsg.Payload, pd.Compress(a.compressType))
197
                                if err != nil {
198
                                        a.logger.Error("unseal message failed", err, watermill.LogFields{
199
                                                watermill.ContextLogFieldKey: ctx,
200
                                        })
201
                                        continue
202
                                }
203
                                wmsg.SetContext(fusCtx.New(fusCtx.Watermill(wmsg.Metadata)))
204
                                msg := &message{Message: wmsg, payload: data}
205
                                if !isRaw {
206
                                        _, msg.obj, _, err = pd.Unseal(wmsg.Payload,
207
                                                pd.Serialize(a.serializeType), pd.Compress(a.compressType))
208
                                        if err != nil {
209
                                                a.logger.Error("unseal message object failed", err, watermill.LogFields{
210
                                                        watermill.ContextLogFieldKey: ctx,
211
                                                })
212
                                                continue
213
                                        }
214
                                }
215
                                select {
216
                                case msgCh <- msg:
217
                                case <-ctx.Done():
218
                                        msg.Nack()
219
                                        a.logger.Info(fmt.Sprintf(
220
                                                "subscriber %s exited with a message nacked when business ctx done", a.name),
221
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
222
                                        return
223
                                case <-a.ctx.Done():
224
                                        msg.Nack()
225
                                        a.logger.Info(fmt.Sprintf(
226
                                                "subscriber %s exited with a message nacked when app ctx done", a.name),
227
                                                watermill.LogFields{watermill.ContextLogFieldKey: ctx})
228
                                        return
229
                                }
230
231
                        case <-ctx.Done():
232
                                return
233
                        case <-a.ctx.Done():
234
                                return
235
                        }
236
                }
237
        }, routine.AppName(a.appName))
238
        return msgCh, err
239
}
func @340:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

340
func(msg *mw.Message) (err error) {
341
                _, data, _, err := pd.Unseal(msg.Payload,
342
                        pd.Serialize(r.serializeType), pd.Compress(r.compressType), pd.Type(typ))
343
                if err != nil {
344
                        return
345
                }
346
                params := unwrapParams(typ, data)
347
                ctx := fusCtx.New(fusCtx.Watermill(msg.Metadata))
348
                return fn(append([]any{ctx}, params...)...)
349
        }
func @117:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

117
func() {
118
                idList := utils.SliceMapping(msgs, func(s *mw.Message) (id string) { return s.UUID })
119
                idList = utils.NewSet(idList...).Items()
120
                retryFunc := func(attempt uint) error {
121
                        if attempt > 1 {
122
                                logInfo(ctx, a.logger, a.appName, a.name,
123
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
124
                                        a.conf.Topic, idList, len(msgs), attempt-1)
125
                        }
126
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
127
                }
128
129
                if err = retry.Retry(retryFunc, opt.asyncStrategies...); err != nil {
130
                        logError(ctx, a.logger, a.appName, a.name,
131
                                "retry to publish topic message failed [err[%s] topic[%s] message%v[%v]]",
132
                                err, a.conf.Topic, idList, len(msgs))
133
                }
134
        }
func @78:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

78
func() {
79
                idList := utils.SliceMapping(msgs, func(s *mw.Message) (id string) { return s.UUID })
80
                idList = utils.NewSet(idList...).Items()
81
                retryFunc := func(attempt uint) error {
82
                        if attempt > 1 {
83
                                logInfo(ctx, a.logger, a.appName, a.name,
84
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
85
                                        a.conf.Topic, idList, len(msgs), attempt-1)
86
                        }
87
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
88
                }
89
90
                if err = retry.Retry(retryFunc, opt.asyncStrategies...); err != nil {
91
                        logError(ctx, a.logger, a.appName, a.name,
92
                                "retry to publish topic message failed [err[%s] topic[%s] message%v[%v]]",
93
                                err, a.conf.Topic, idList, len(msgs))
94
                }
95
        }
func @113:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

113
func(counts gobreaker.Counts) bool {
114
                                        // fallback to default ready to trip expression
115
                                        if expr == nil {
116
                                                return counts.ConsecutiveFailures > 5
117
                                        }
118
                                        if ok, err := expr.EvalBool(ctx, map[string]uint32{
119
                                                "requests":              counts.Requests,
120
                                                "total_successes":       counts.TotalSuccesses,
121
                                                "total_failures":        counts.TotalFailures,
122
                                                "consecutive_successes": counts.ConsecutiveSuccesses,
123
                                                "consecutive_failures":  counts.ConsecutiveFailures,
124
                                        }); err == nil {
125
                                                return ok
126
                                        }
127
                                        // fallback to default ready to trip expression
128
                                        return counts.ConsecutiveFailures > 5
129
                                }
func event[T].toTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

243
func (e *event[T]) toTime(timestr, locationstr string) (t time.Time) {
244
        loc, err := time.LoadLocation(locationstr)
245
        if err != nil {
246
                loc = constant.DefaultLocation()
247
        }
248
        t, _ = time.ParseInLocation(time.RFC3339Nano, timestr, loc)
249
        return
250
}
func @220:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

220
func(wmsg *mw.Message) (err error) {
221
                                msg, err := messageConvertFrom(wmsg, r.serializeType, r.compressType)
222
                                if err != nil {
223
                                        return
224
                                }
225
                                return fn(msg)
226
                        }
func event[T].Nack
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

236
func (e *event[T]) Nack() bool {
237
        if e.nackfn != nil {
238
                return e.nackfn()
239
        }
240
        return true
241
}
func @120:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

120
func(attempt uint) error {
121
                        if attempt > 1 {
122
                                logInfo(ctx, a.logger, a.appName, a.name,
123
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
124
                                        a.conf.Topic, idList, len(msgs), attempt-1)
125
                        }
126
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
127
                }
func @150:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

150
func(o *pubOption) {
151
                o.objects = objects
152
                if objectUUIDGenFunc != nil {
153
                        o.objectUUIDGenFunc = reflect.ValueOf(objectUUIDGenFunc)
154
                }
155
        }
func @81:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

81
func(attempt uint) error {
82
                        if attempt > 1 {
83
                                logInfo(ctx, a.logger, a.appName, a.name,
84
                                        "retry to publish topic message [topic[%s] message%v[%v] attempt[%v]]",
85
                                        a.conf.Topic, idList, len(msgs), attempt-1)
86
                        }
87
                        return a.pub.Publish(ctx, a.conf.Topic, msgs...)
88
                }
func router.handle
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

337
func (r *router) handle(hdr any) mw.NoPublishHandlerFunc {
338
        typ := wrapParams(hdr)
339
        fn := utils.WrapFunc1[error](hdr)
340
        return func(msg *mw.Message) (err error) {
341
                _, data, _, err := pd.Unseal(msg.Payload,
342
                        pd.Serialize(r.serializeType), pd.Compress(r.compressType), pd.Type(typ))
343
                if err != nil {
344
                        return
345
                }
346
                params := unwrapParams(typ, data)
347
                ctx := fusCtx.New(fusCtx.Watermill(msg.Metadata))
348
                return fn(append([]any{ctx}, params...)...)
349
        }
350
}
func unwrapParams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/utils.go:

21
func unwrapParams(typ reflect.Type, arg any) (params []any) {
22
        if typ == nil {
23
                return
24
        }
25
26
        return []any{arg}
27
}
func @166:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

166
func(o *pubOption) {
167
                o.async = true
168
                o.asyncStrategies = strategies
169
        }
func @252:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

252
func(msg *mw.Message) error {
253
                                        rets := fnVal.Convert(watermillHandlerFuncType).Call(
254
                                                []reflect.Value{reflect.ValueOf(rawMessageConvertFrom(msg))},
255
                                        )
256
                                        return utils.ParseVariadicFuncResult[error](rets, 0)
257
                                }
func @264:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

264
func(msg *mw.Message) error {
265
                                        rets := fnVal.
266
                                                Convert(watermillNoPublishHandlerFuncType).
267
                                                Call([]reflect.Value{reflect.ValueOf(msg)})
268
                                        return utils.ParseVariadicFuncResult[error](rets, 0)
269
                                }
func formatLogMsg
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

45
func formatLogMsg(app, n, src string, args ...any) (dst string) {
46
        appName := config.Use(app).AppName()
47
        return fmt.Sprintf("%v [Gofusion] %s %s %s %s",
48
                syscall.Getpid(), appName, config.ComponentMessageQueue, n, fmt.Sprintf(src, args...))
49
}
func event[T].DeletedAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

228
func (e *event[T]) DeletedAt() time.Time     { return e.toTime(e.pd.D, e.pd.DL) }
func logDebug
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

21
func logDebug(ctx context.Context, l watermill.LoggerAdapter, app, n, m string, args ...any) {
22
        l.Debug(formatLogMsg(app, n, m, args...), formatFields(ctx))
23
}
func @79:38
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

79
func(s *mw.Message) (id string) { return s.UUID }
func @118:38
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

118
func(s *mw.Message) (id string) { return s.UUID }
func @133:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

133
func(err error) bool { return err == nil }
func event[T].UpdatedAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

227
func (e *event[T]) UpdatedAt() time.Time     { return e.toTime(e.pd.U, e.pd.UL) }
func event[T].CreatedAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

226
func (e *event[T]) CreatedAt() time.Time     { return e.toTime(e.pd.C, e.pd.CL) }
func EventDeleted
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

184
func EventDeleted[T eventual](id string, deletedAt time.Time, payload T) Event[T] {
185
        return newEvent[T](id, time.Time{}, time.Time{}, deletedAt, payload)
186
}
func EventUpdated
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

181
func EventUpdated[T eventual](id string, updatedAt time.Time, payload T) Event[T] {
182
        return newEvent[T](id, time.Time{}, updatedAt, time.Time{}, payload)
183
}
func Objects
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

149
func Objects[T any](objectUUIDGenFunc func(T) string, objects ...any) utils.OptionFunc[pubOption] {
150
        return func(o *pubOption) {
151
                o.objects = objects
152
                if objectUUIDGenFunc != nil {
153
                        o.objectUUIDGenFunc = reflect.ValueOf(objectUUIDGenFunc)
154
                }
155
        }
156
}
func EventCreated
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

178
func EventCreated[T eventual](id string, createdAt time.Time, payload T) Event[T] {
179
        return newEvent[T](id, createdAt, time.Time{}, time.Time{}, payload)
180
}
func NewEvent
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

172
func NewEvent[T eventual](id string, createdAt, updatedAt, deletedAt time.Time, payload T) Event[T] {
173
        return newEvent[T](id, createdAt, updatedAt, deletedAt, payload)
174
}
func @150:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

150
func() IRouter { return Use(name, AppName(opt.AppName)) }
func @102:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

102
func() EventSubscriber[T] {
103
                return NewEventSubscriber[T](name, opts...)
104
        }
func NewEventSubscriberDI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

101
func NewEventSubscriberDI[T eventual](name string, opts ...utils.OptionExtender) func() EventSubscriber[T] {
102
        return func() EventSubscriber[T] {
103
                return NewEventSubscriber[T](name, opts...)
104
        }
105
}
func Async
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

165
func Async(strategies ...strategy.Strategy) utils.OptionFunc[pubOption] {
166
        return func(o *pubOption) {
167
                o.async = true
168
                o.asyncStrategies = strategies
169
        }
170
}
func @130:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

130
func(name string, from gobreaker.State, to gobreaker.State) {
131
                                        logInfo(ctx, logger, appName, name, "circuit breaker state changed: %s -> %s", from, to)
132
                                }
func @62:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

62
func() EventPublisher[T] {
63
                return NewEventPublisher[T](name, opts...)
64
        }
func NewEventPublisherDI
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/event.go:

61
func NewEventPublisherDI[T eventual](name string, opts ...utils.OptionExtender) func() EventPublisher[T] {
62
        return func() EventPublisher[T] {
63
                return NewEventPublisher[T](name, opts...)
64
        }
65
}
func @77:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

77
func(attempt int, delay time.Duration) {
78
                                        logTrace(ctx, logger, appName, name,
79
                                                "retry to consume message [attempt[%v] delay[%s]]", attempt, delay)
80
                                }
func @169:23
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

169
func() Publisher { return Pub(name, AppName(opt.AppName)) }
func kafkaOAuthProvider.Token
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/kafka.go:

137
func (k *kafkaOAuthProvider) Token() (*sarama.AccessToken, error) {
138
        return &sarama.AccessToken{Token: k.token}, nil
139
}
func @149:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/construct.go:

149
func() Subscriber { return sub(name, AppName(opt.AppName)) }
func abstractMQ.close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

241
func (a *abstractMQ) close() error                             { panic(ErrNotImplement) }
func abstractMQ.watermillLogger
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/mq.go:

245
func (a *abstractMQ) watermillLogger() watermill.LoggerAdapter { return a.logger }
func logError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

15
func logError(ctx context.Context, l watermill.LoggerAdapter, app, n, m string, args ...any) {
16
        l.Error(formatLogMsg(app, n, m, args...), nil, formatFields(ctx))
17
}
func message.RawMessage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

209
func (m *message) RawMessage() any { return m.Message }
func message.Object
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/types.go:

210
func (m *message) Object() any     { return m.obj }
func logInfo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

18
func logInfo(ctx context.Context, l watermill.LoggerAdapter, app, n, m string, args ...any) {
19
        l.Info(formatLogMsg(app, n, m, args...), formatFields(ctx))
20
}
func logTrace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/log.go:

24
func logTrace(ctx context.Context, l watermill.LoggerAdapter, app, n, m string, args ...any) {
25
        l.Trace(formatLogMsg(app, n, m, args...), formatFields(ctx))
26
}
func @93:29
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/mq/router.go:

93
func(err error) bool { return err != nil }
Package Overview: github.com/wfusion/gofusion/redis 23.4%

Please select a function to see what's left for testing.

startDaemonRoutines(...) github.com/wfusion/gofusion/redis/metrics.go 100.0% 10/10
Construct(...) github.com/wfusion/gofusion/redis/construct.go 100.0% 7/7
instance.XAdd(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Subscribe(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/redis/construct.go 100.0% 1/1
instance.MGet(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Set(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.SetNX(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Del(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.XAck(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.GetProxy(...) github.com/wfusion/gofusion/redis/redis.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/redis/redis.go 100.0% 1/1
@39:9(...) github.com/wfusion/gofusion/redis/redis.go 100.0% 1/1
instance.SAdd(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Pipeline(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.EvalSha(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Get(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.ZRem(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.ZAdd(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.XClaim(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.XPendingExt(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.XReadGroup(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.XGroupCreateMkStream(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Eval(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
instance.Keys(...) github.com/wfusion/gofusion/redis/wrap.go 100.0% 1/1
addInstance(...) github.com/wfusion/gofusion/redis/construct.go 91.3% 21/23
@31:9(...) github.com/wfusion/gofusion/redis/construct.go 88.9% 8/9
Use(...) github.com/wfusion/gofusion/redis/redis.go 80.0% 8/10
metricRedisLatency(...) github.com/wfusion/gofusion/redis/metrics.go 66.7% 2/3
metricRedisStats(...) github.com/wfusion/gofusion/redis/metrics.go 66.7% 2/3
@61:21(...) github.com/wfusion/gofusion/redis/metrics.go 51.6% 16/31
@114:21(...) github.com/wfusion/gofusion/redis/metrics.go 50.0% 10/20
instance.Persist(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireNX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireXX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireGT(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireLT(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireTime(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Migrate(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Move(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ObjectRefCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ObjectEncoding(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ObjectIdleTime(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ExpireAt(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PExpire(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PExpireAt(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PExpireTime(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PTTL(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RandomKey(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Rename(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RenameNX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Restore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RestoreReplace(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Sort(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SortRO(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SortStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SortInterfaces(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Touch(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.TTL(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Type(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Append(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Decr(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.DecrBy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Expire(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GetRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GetSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GetEx(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GetDel(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Incr(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.IncrBy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.IncrByFloat(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Exists(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.MSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.MSetNX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Dump(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SetArgs(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SetEx(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SetXX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SetRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.StrLen(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Copy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GetBit(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SetBit(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitOpAnd(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitOpOr(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitOpXor(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitOpNot(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitPos(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitPosSpan(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BitField(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Scan(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ScanType(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SScan(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HScan(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZScan(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HDel(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HExists(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HGet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HGetAll(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HIncrBy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HIncrByFloat(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HKeys(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HLen(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HMGet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HMSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HSetNX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HVals(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HRandField(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.HRandFieldWithValues(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BLPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BLMPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BRPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BRPopLPush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LCS(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LIndex(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LMPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LInsert(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LInsertBefore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LInsertAfter(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LLen(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPopCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPos(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPosCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LPushX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LRem(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Quit(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RPopCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RPopLPush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RPush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.RPushX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LMove(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BLMove(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Ping(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SCard(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SDiff(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SDiffStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SInter(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SInterCard(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SInterStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SIsMember(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SMIsMember(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SMembers(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SMembersMap(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SMove(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SPopN(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SRandMember(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SRandMemberN(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SRem(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SUnion(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SUnionStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Echo(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XDel(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XLen(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XRangeN(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XRevRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XRevRangeN(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XRead(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XReadStreams(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XGroupCreate(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientGetName(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XGroupSetID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XGroupDestroy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XGroupCreateConsumer(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XGroupDelConsumer(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.CommandGetKeysAndFlags(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LTrim(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XPending(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.CommandGetKeys(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.CommandList(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XClaimJustID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XAutoClaim(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XAutoClaimJustID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XTrimMaxLen(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XTrimMaxLenApprox(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XTrimMinID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XTrimMinIDApprox(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XInfoGroups(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XInfoStream(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XInfoStreamFull(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.XInfoConsumers(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BZPopMax(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BZPopMin(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BZMPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Command(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddLT(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddGT(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddNX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddXX(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddArgs(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZAddArgsIncr(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZCard(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZLexCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZIncrBy(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZInter(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZInterWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZInterCard(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZInterStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZMPop(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZMScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZPopMax(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZPopMin(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeByScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeByLex(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeByScoreWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeArgs(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeArgsWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRangeStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRank(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRankWithScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.TxPipeline(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRemRangeByRank(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRemRangeByScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRemRangeByLex(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRangeWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRangeByScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRangeByLex(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRangeByScoreWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRank(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRevRankWithScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZScore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZUnionStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRandMember(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZRandMemberWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZUnion(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZUnionWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZDiff(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZDiffWithScores(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ZDiffStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PFAdd(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PFCount(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PFMerge(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BgRewriteAOF(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.BgSave(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientKill(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientKillByFilter(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientList(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientPause(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientUnpause(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientUnblock(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientUnblockWithError(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClientInfo(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ConfigGet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ConfigResetStat(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ConfigSet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ConfigRewrite(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.DBSize(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FlushAll(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FlushAllAsync(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FlushDB(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FlushDBAsync(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Info(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.LastSave(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Save(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Shutdown(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ShutdownSave(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ShutdownNoSave(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SlaveOf(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SlowLogGet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Time(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.DebugObject(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ReadOnly(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ReadWrite(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.MemoryUsage(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.TxPipelined(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Pipelined(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.EvalRO(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.EvalShaRO(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ScriptExists(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ScriptFlush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ScriptKill(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ScriptLoad(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionLoad(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionLoadReplace(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionDelete(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionFlush(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionKill(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionFlushAsync(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionList(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionDump(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionRestore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FunctionStats(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FCall(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FCallRo(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.FCallRO(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Publish(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SPublish(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PubSubChannels(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PubSubNumSub(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PubSubNumPat(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PubSubShardChannels(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PubSubShardNumSub(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterMyShardID(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterSlots(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterShards(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterNodes(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterMeet(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterForget(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterReplicate(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterResetSoft(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterResetHard(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterInfo(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterKeySlot(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterGetKeysInSlot(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterCountFailureReports(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterCountKeysInSlot(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterDelSlots(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterDelSlotsRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterSaveConfig(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterSlaves(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterFailover(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterAddSlots(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ClusterAddSlotsRange(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoAdd(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoPos(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoRadius(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoRadiusStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoRadiusByMember(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoRadiusByMemberStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoSearch(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoSearchLocation(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoSearchStore(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoDist(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.GeoHash(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ACLDryRun(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.ModuleLoadex(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.AddHook(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Watch(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Do(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Process(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
@83:22(...) github.com/wfusion/gofusion/redis/construct.go 0.0% 0/1
instance.PSubscribe(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.SSubscribe(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.Close(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
instance.PoolStats(...) github.com/wfusion/gofusion/redis/wrap.go 0.0% 0/1
func startDaemonRoutines
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/metrics.go:

31
func startDaemonRoutines(ctx context.Context, appName, name string, conf *Conf) {
32
        ticker := time.Tick(time.Second * 5)
33
        app := config.Use(appName).AppName()
34
        labels := []metrics.Label{
35
                {Key: "config", Value: name},
36
                {Key: "database", Value: cast.ToString(conf.DB)},
37
        }
38
39
        log.Printf("%v [Gofusion] %s %s %s metrics start", syscall.Getpid(), app, config.ComponentRedis, name)
40
        for {
41
                select {
42
                case <-ctx.Done():
43
                        log.Printf("%v [Gofusion] %s %s %s metrics exited",
44
                                syscall.Getpid(), app, config.ComponentRedis, name)
45
                        return
46
                case <-ticker:
47
                        go metricRedisStats(ctx, appName, name, labels)
48
                        go metricRedisLatency(ctx, appName, name, labels)
49
                }
50
        }
51
}
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/construct.go:

21
func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() {
22
        opt := utils.ApplyOptions[config.InitOption](opts...)
23
        optU := utils.ApplyOptions[useOption](opts...)
24
        if opt.AppName == "" {
25
                opt.AppName = optU.appName
26
        }
27
28
        for name, conf := range confs {
29
                addInstance(ctx, name, conf, opt)
30
        }
31
        return func() {
32
                rwlock.Lock()
33
                defer rwlock.Unlock()
34
35
                pid := syscall.Getpid()
36
                app := config.Use(opt.AppName).AppName()
37
                if appInstances != nil {
38
                        for name, instance := range appInstances[opt.AppName] {
39
                                if err := instance.GetProxy().Close(); err != nil {
40
                                        log.Printf("%v [Gofusion] %s %s %s close error: %s",
41
                                                pid, app, config.ComponentRedis, name, err)
42
                                }
43
                        }
44
                        delete(appInstances, opt.AppName)
45
                }
46
        }
47
}
func instance.XAdd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

452
func (i *instance) XAdd(ctx context.Context, a *rdsDrv.XAddArgs) *rdsDrv.StringCmd {
453
        return i.GetProxy().XAdd(ctx, a)
454
}
func instance.Subscribe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1015
func (i *instance) Subscribe(ctx context.Context, channels ...string) *rdsDrv.PubSub {
1016
        return i.GetProxy().Subscribe(ctx, channels...)
1017
}
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/construct.go:

89
func init() {
90
        config.AddComponent(config.ComponentRedis, Construct)
91
}
func instance.MGet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

182
func (i *instance) MGet(ctx context.Context, keys ...string) *rdsDrv.SliceCmd {
183
        return i.GetProxy().MGet(ctx, keys...)
184
}
func instance.Set
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

191
func (i *instance) Set(ctx context.Context, key string, value any, expiration time.Duration) *rdsDrv.StatusCmd {
192
        return i.GetProxy().Set(ctx, key, value, expiration)
193
}
func instance.SetNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

201
func (i *instance) SetNX(ctx context.Context, key string, value any, expiration time.Duration) *rdsDrv.BoolCmd {
202
        return i.GetProxy().SetNX(ctx, key, value, expiration)
203
}
func instance.Del
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

46
func (i *instance) Del(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
47
        return i.GetProxy().Del(ctx, keys...)
48
}
func instance.XAck
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

501
func (i *instance) XAck(ctx context.Context, stream, group string, ids ...string) *rdsDrv.IntCmd {
502
        return i.GetProxy().XAck(ctx, stream, group, ids...)
503
}
func instance.GetProxy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/redis.go:

25
func (i *instance) GetProxy() rdsDrv.UniversalClient {
26
        return i.redis.GetProxy()
27
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/redis.go:

38
func AppName(name string) utils.OptionFunc[useOption] {
39
        return func(o *useOption) {
40
                o.appName = name
41
        }
42
}
func @39:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/redis.go:

39
func(o *useOption) {
40
                o.appName = name
41
        }
func instance.SAdd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

395
func (i *instance) SAdd(ctx context.Context, key string, members ...any) *rdsDrv.IntCmd {
396
        return i.GetProxy().SAdd(ctx, key, members...)
397
}
func instance.Pipeline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

10
func (i *instance) Pipeline() rdsDrv.Pipeliner {
11
        return i.GetProxy().Pipeline()
12
}
func instance.EvalSha
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

811
func (i *instance) EvalSha(ctx context.Context, sha1 string, keys []string, args ...any) *rdsDrv.Cmd {
812
        return i.GetProxy().EvalSha(ctx, sha1, keys, args...)
813
}
func instance.Get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

158
func (i *instance) Get(ctx context.Context, key string) *rdsDrv.StringCmd {
159
        return i.GetProxy().Get(ctx, key)
160
}
func instance.ZRem
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

644
func (i *instance) ZRem(ctx context.Context, key string, members ...any) *rdsDrv.IntCmd {
645
        return i.GetProxy().ZRem(ctx, key, members...)
646
}
func instance.ZAdd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

556
func (i *instance) ZAdd(ctx context.Context, key string, members ...rdsDrv.Z) *rdsDrv.IntCmd {
557
        return i.GetProxy().ZAdd(ctx, key, members...)
558
}
func instance.XClaim
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

510
func (i *instance) XClaim(ctx context.Context, a *rdsDrv.XClaimArgs) *rdsDrv.XMessageSliceCmd {
511
        return i.GetProxy().XClaim(ctx, a)
512
}
func instance.XPendingExt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

507
func (i *instance) XPendingExt(ctx context.Context, a *rdsDrv.XPendingExtArgs) *rdsDrv.XPendingExtCmd {
508
        return i.GetProxy().XPendingExt(ctx, a)
509
}
func instance.XReadGroup
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

498
func (i *instance) XReadGroup(ctx context.Context, a *rdsDrv.XReadGroupArgs) *rdsDrv.XStreamSliceCmd {
499
        return i.GetProxy().XReadGroup(ctx, a)
500
}
func instance.XGroupCreateMkStream
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

483
func (i *instance) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *rdsDrv.StatusCmd {
484
        return i.GetProxy().XGroupCreateMkStream(ctx, stream, group, start)
485
}
func instance.Eval
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

808
func (i *instance) Eval(ctx context.Context, script string, keys []string, args ...any) *rdsDrv.Cmd {
809
        return i.GetProxy().Eval(ctx, script, keys, args...)
810
}
func instance.Keys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

79
func (i *instance) Keys(ctx context.Context, pattern string) *rdsDrv.StringSliceCmd {
80
        return i.GetProxy().Keys(ctx, pattern)
81
}
func addInstance
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/construct.go:

49
func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) {
50
        var hooks []rdsDrv.Hook
51
        for _, hookLoc := range conf.Hooks {
52
                if hookType := inspect.TypeOf(hookLoc); hookType != nil {
53
                        hookValue := reflect.New(hookType)
54
                        if hookValue.Type().Implements(customLoggerType) {
55
                                logger := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
56
                                hookValue.Interface().(customLogger).Init(logger, opt.AppName, name)
57
                        }
58
59
                        hooks = append(hooks, hookValue.Interface().(rdsDrv.Hook))
60
                }
61
        }
62
63
        // conf.Option.Password = config.CryptoDecryptFunc()(conf.Option.Password)
64
        rdsCli, err := redis.Default.New(ctx, conf.Option, redis.WithHook(hooks))
65
        if err != nil {
66
                panic(err)
67
        }
68
69
        rwlock.Lock()
70
        defer rwlock.Unlock()
71
        if appInstances == nil {
72
                appInstances = make(map[string]map[string]*instance)
73
        }
74
        if appInstances[opt.AppName] == nil {
75
                appInstances[opt.AppName] = make(map[string]*instance)
76
        }
77
        if _, ok := appInstances[opt.AppName][name]; ok {
78
                panic(ErrDuplicatedName)
79
        }
80
        appInstances[opt.AppName][name] = &instance{name: name, redis: rdsCli}
81
82
        if opt.DI != nil {
83
                opt.DI.MustProvide(func() rdsDrv.UniversalClient { return Use(ctx, name, AppName(opt.AppName)) }, di.Name(name))
84
        }
85
86
        go startDaemonRoutines(ctx, opt.AppName, name, conf)
87
}
func @31:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/construct.go:

31
func() {
32
                rwlock.Lock()
33
                defer rwlock.Unlock()
34
35
                pid := syscall.Getpid()
36
                app := config.Use(opt.AppName).AppName()
37
                if appInstances != nil {
38
                        for name, instance := range appInstances[opt.AppName] {
39
                                if err := instance.GetProxy().Close(); err != nil {
40
                                        log.Printf("%v [Gofusion] %s %s %s close error: %s",
41
                                                pid, app, config.ComponentRedis, name, err)
42
                                }
43
                        }
44
                        delete(appInstances, opt.AppName)
45
                }
46
        }
func Use
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/redis.go:

44
func Use(ctx context.Context, name string, opts ...utils.OptionExtender) rdsDrv.UniversalClient {
45
        opt := utils.ApplyOptions[useOption](opts...)
46
47
        rwlock.RLock()
48
        defer rwlock.RUnlock()
49
        instances, ok := appInstances[opt.appName]
50
        if !ok {
51
                panic(errors.Errorf("redis instance not found for app: %s", opt.appName))
52
        }
53
        instance, ok := instances[name]
54
        if !ok {
55
                panic(errors.Errorf("redis instance not found for name: %s", name))
56
        }
57
        return &Redis{UniversalClient: instance, Name: name}
58
}
func metricRedisLatency
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/metrics.go:

106
func metricRedisLatency(ctx context.Context, appName, name string, labels []metrics.Label) {
107
        select {
108
        case <-ctx.Done():
109
                return
110
        default:
111
112
        }
113
114
        _, _ = utils.Catch(func() {
115
                rwlock.RLock()
116
                defer rwlock.RUnlock()
117
                instances, ok := appInstances[appName]
118
                if !ok {
119
                        return
120
                }
121
                instance, ok := instances[name]
122
                if !ok {
123
                        return
124
                }
125
126
                rdsCli := instance.GetProxy()
127
                begin := time.Now()
128
                if err := rdsCli.Ping(ctx); err != nil {
129
                        return
130
                }
131
132
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
133
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
134
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
135
                        select {
136
                        case <-ctx.Done():
137
                                return
138
                        default:
139
                                if m.IsEnableServiceLabel() {
140
                                        m.AddSample(ctx, latencyKey, latency,
141
                                                metrics.Labels(labels),
142
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
143
                                        )
144
                                } else {
145
                                        m.AddSample(ctx, metricsLatencyKey, latency,
146
                                                metrics.Labels(labels),
147
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
148
                                        )
149
                                }
150
                        }
151
                }
152
        })
153
}
func metricRedisStats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/metrics.go:

53
func metricRedisStats(ctx context.Context, appName, name string, labels []metrics.Label) {
54
        select {
55
        case <-ctx.Done():
56
                return
57
        default:
58
59
        }
60
61
        _, _ = utils.Catch(func() {
62
                rwlock.RLock()
63
                defer rwlock.RUnlock()
64
                _ = appInstances[appName][name].GetProxy()
65
                instances, ok := appInstances[appName]
66
                if !ok {
67
                        return
68
                }
69
                instance, ok := instances[name]
70
                if !ok {
71
                        return
72
                }
73
74
                app := config.Use(appName).AppName()
75
                idleKey := append([]string{app}, metricsPoolIdleKey...)
76
                staleKey := append([]string{app}, metricsPoolStaleKey...)
77
                totalKey := append([]string{app}, metricsPoolTotalKey...)
78
                hitsKey := append([]string{app}, metricsPoolHitsKey...)
79
                missesKey := append([]string{app}, metricsPoolMissesKey...)
80
81
                rdsCli := instance.GetProxy()
82
                stats := rdsCli.PoolStats()
83
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
84
                        select {
85
                        case <-ctx.Done():
86
                                return
87
                        default:
88
                                if m.IsEnableServiceLabel() {
89
                                        m.SetGauge(ctx, idleKey, float64(stats.IdleConns), metrics.Labels(labels))
90
                                        m.SetGauge(ctx, staleKey, float64(stats.StaleConns), metrics.Labels(labels))
91
                                        m.SetGauge(ctx, totalKey, float64(stats.TotalConns), metrics.Labels(labels))
92
                                        m.SetGauge(ctx, hitsKey, float64(stats.Hits), metrics.Labels(labels))
93
                                        m.SetGauge(ctx, missesKey, float64(stats.Misses), metrics.Labels(labels))
94
                                } else {
95
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(stats.IdleConns), metrics.Labels(labels))
96
                                        m.SetGauge(ctx, metricsPoolStaleKey, float64(stats.StaleConns), metrics.Labels(labels))
97
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(stats.TotalConns), metrics.Labels(labels))
98
                                        m.SetGauge(ctx, metricsPoolHitsKey, float64(stats.Hits), metrics.Labels(labels))
99
                                        m.SetGauge(ctx, metricsPoolMissesKey, float64(stats.Misses), metrics.Labels(labels))
100
                                }
101
                        }
102
                }
103
        })
104
}
func @61:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/metrics.go:

61
func() {
62
                rwlock.RLock()
63
                defer rwlock.RUnlock()
64
                _ = appInstances[appName][name].GetProxy()
65
                instances, ok := appInstances[appName]
66
                if !ok {
67
                        return
68
                }
69
                instance, ok := instances[name]
70
                if !ok {
71
                        return
72
                }
73
74
                app := config.Use(appName).AppName()
75
                idleKey := append([]string{app}, metricsPoolIdleKey...)
76
                staleKey := append([]string{app}, metricsPoolStaleKey...)
77
                totalKey := append([]string{app}, metricsPoolTotalKey...)
78
                hitsKey := append([]string{app}, metricsPoolHitsKey...)
79
                missesKey := append([]string{app}, metricsPoolMissesKey...)
80
81
                rdsCli := instance.GetProxy()
82
                stats := rdsCli.PoolStats()
83
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
84
                        select {
85
                        case <-ctx.Done():
86
                                return
87
                        default:
88
                                if m.IsEnableServiceLabel() {
89
                                        m.SetGauge(ctx, idleKey, float64(stats.IdleConns), metrics.Labels(labels))
90
                                        m.SetGauge(ctx, staleKey, float64(stats.StaleConns), metrics.Labels(labels))
91
                                        m.SetGauge(ctx, totalKey, float64(stats.TotalConns), metrics.Labels(labels))
92
                                        m.SetGauge(ctx, hitsKey, float64(stats.Hits), metrics.Labels(labels))
93
                                        m.SetGauge(ctx, missesKey, float64(stats.Misses), metrics.Labels(labels))
94
                                } else {
95
                                        m.SetGauge(ctx, metricsPoolIdleKey, float64(stats.IdleConns), metrics.Labels(labels))
96
                                        m.SetGauge(ctx, metricsPoolStaleKey, float64(stats.StaleConns), metrics.Labels(labels))
97
                                        m.SetGauge(ctx, metricsPoolTotalKey, float64(stats.TotalConns), metrics.Labels(labels))
98
                                        m.SetGauge(ctx, metricsPoolHitsKey, float64(stats.Hits), metrics.Labels(labels))
99
                                        m.SetGauge(ctx, metricsPoolMissesKey, float64(stats.Misses), metrics.Labels(labels))
100
                                }
101
                        }
102
                }
103
        }
func @114:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/metrics.go:

114
func() {
115
                rwlock.RLock()
116
                defer rwlock.RUnlock()
117
                instances, ok := appInstances[appName]
118
                if !ok {
119
                        return
120
                }
121
                instance, ok := instances[name]
122
                if !ok {
123
                        return
124
                }
125
126
                rdsCli := instance.GetProxy()
127
                begin := time.Now()
128
                if err := rdsCli.Ping(ctx); err != nil {
129
                        return
130
                }
131
132
                latency := float64(time.Since(begin)) / float64(time.Millisecond)
133
                latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
134
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
135
                        select {
136
                        case <-ctx.Done():
137
                                return
138
                        default:
139
                                if m.IsEnableServiceLabel() {
140
                                        m.AddSample(ctx, latencyKey, latency,
141
                                                metrics.Labels(labels),
142
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
143
                                        )
144
                                } else {
145
                                        m.AddSample(ctx, metricsLatencyKey, latency,
146
                                                metrics.Labels(labels),
147
                                                metrics.PrometheusBuckets(metricsLatencyBuckets),
148
                                        )
149
                                }
150
                        }
151
                }
152
        }
func instance.Persist
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

98
func (i *instance) Persist(ctx context.Context, key string) *rdsDrv.BoolCmd {
99
        return i.GetProxy().Persist(ctx, key)
100
}
func instance.ExpireNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

67
func (i *instance) ExpireNX(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
68
        return i.GetProxy().ExpireNX(ctx, key, expiration)
69
}
func instance.ExpireXX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

70
func (i *instance) ExpireXX(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
71
        return i.GetProxy().ExpireXX(ctx, key, expiration)
72
}
func instance.ExpireGT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

73
func (i *instance) ExpireGT(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
74
        return i.GetProxy().ExpireGT(ctx, key, expiration)
75
}
func instance.ExpireLT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

76
func (i *instance) ExpireLT(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
77
        return i.GetProxy().ExpireLT(ctx, key, expiration)
78
}
func instance.ExpireTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

64
func (i *instance) ExpireTime(ctx context.Context, key string) *rdsDrv.DurationCmd {
65
        return i.GetProxy().ExpireTime(ctx, key)
66
}
func instance.Migrate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

82
func (i *instance) Migrate(ctx context.Context, host, port, key string, db int,
83
        timeout time.Duration) *rdsDrv.StatusCmd {
84
        return i.GetProxy().Migrate(ctx, host, port, key, db, timeout)
85
}
func instance.Move
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

86
func (i *instance) Move(ctx context.Context, key string, db int) *rdsDrv.BoolCmd {
87
        return i.GetProxy().Move(ctx, key, db)
88
}
func instance.ObjectRefCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

89
func (i *instance) ObjectRefCount(ctx context.Context, key string) *rdsDrv.IntCmd {
90
        return i.GetProxy().ObjectRefCount(ctx, key)
91
}
func instance.ObjectEncoding
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

92
func (i *instance) ObjectEncoding(ctx context.Context, key string) *rdsDrv.StringCmd {
93
        return i.GetProxy().ObjectEncoding(ctx, key)
94
}
func instance.ObjectIdleTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

95
func (i *instance) ObjectIdleTime(ctx context.Context, key string) *rdsDrv.DurationCmd {
96
        return i.GetProxy().ObjectIdleTime(ctx, key)
97
}
func instance.ExpireAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

61
func (i *instance) ExpireAt(ctx context.Context, key string, tm time.Time) *rdsDrv.BoolCmd {
62
        return i.GetProxy().ExpireAt(ctx, key, tm)
63
}
func instance.PExpire
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

101
func (i *instance) PExpire(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
102
        return i.GetProxy().PExpire(ctx, key, expiration)
103
}
func instance.PExpireAt
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

104
func (i *instance) PExpireAt(ctx context.Context, key string, tm time.Time) *rdsDrv.BoolCmd {
105
        return i.GetProxy().PExpireAt(ctx, key, tm)
106
}
func instance.PExpireTime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

107
func (i *instance) PExpireTime(ctx context.Context, key string) *rdsDrv.DurationCmd {
108
        return i.GetProxy().PExpireTime(ctx, key)
109
}
func instance.PTTL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

110
func (i *instance) PTTL(ctx context.Context, key string) *rdsDrv.DurationCmd {
111
        return i.GetProxy().PTTL(ctx, key)
112
}
func instance.RandomKey
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

113
func (i *instance) RandomKey(ctx context.Context) *rdsDrv.StringCmd {
114
        return i.GetProxy().RandomKey(ctx)
115
}
func instance.Rename
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

116
func (i *instance) Rename(ctx context.Context, key, newkey string) *rdsDrv.StatusCmd {
117
        return i.GetProxy().Rename(ctx, key, newkey)
118
}
func instance.RenameNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

119
func (i *instance) RenameNX(ctx context.Context, key, newkey string) *rdsDrv.BoolCmd {
120
        return i.GetProxy().RenameNX(ctx, key, newkey)
121
}
func instance.Restore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

122
func (i *instance) Restore(ctx context.Context, key string, ttl time.Duration, value string) *rdsDrv.StatusCmd {
123
        return i.GetProxy().Restore(ctx, key, ttl, value)
124
}
func instance.RestoreReplace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

125
func (i *instance) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *rdsDrv.StatusCmd {
126
        return i.GetProxy().RestoreReplace(ctx, key, ttl, value)
127
}
func instance.Sort
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

128
func (i *instance) Sort(ctx context.Context, key string, sort *rdsDrv.Sort) *rdsDrv.StringSliceCmd {
129
        return i.GetProxy().Sort(ctx, key, sort)
130
}
func instance.SortRO
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

131
func (i *instance) SortRO(ctx context.Context, key string, sort *rdsDrv.Sort) *rdsDrv.StringSliceCmd {
132
        return i.GetProxy().SortRO(ctx, key, sort)
133
}
func instance.SortStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

134
func (i *instance) SortStore(ctx context.Context, key, store string, sort *rdsDrv.Sort) *rdsDrv.IntCmd {
135
        return i.GetProxy().SortStore(ctx, key, store, sort)
136
}
func instance.SortInterfaces
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

137
func (i *instance) SortInterfaces(ctx context.Context, key string, sort *rdsDrv.Sort) *rdsDrv.SliceCmd {
138
        return i.GetProxy().SortInterfaces(ctx, key, sort)
139
}
func instance.Touch
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

140
func (i *instance) Touch(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
141
        return i.GetProxy().Touch(ctx, keys...)
142
}
func instance.TTL
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

143
func (i *instance) TTL(ctx context.Context, key string) *rdsDrv.DurationCmd {
144
        return i.GetProxy().TTL(ctx, key)
145
}
func instance.Type
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

146
func (i *instance) Type(ctx context.Context, key string) *rdsDrv.StatusCmd {
147
        return i.GetProxy().Type(ctx, key)
148
}
func instance.Append
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

149
func (i *instance) Append(ctx context.Context, key, value string) *rdsDrv.IntCmd {
150
        return i.GetProxy().Append(ctx, key, value)
151
}
func instance.Decr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

152
func (i *instance) Decr(ctx context.Context, key string) *rdsDrv.IntCmd {
153
        return i.GetProxy().Decr(ctx, key)
154
}
func instance.DecrBy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

155
func (i *instance) DecrBy(ctx context.Context, key string, decrement int64) *rdsDrv.IntCmd {
156
        return i.GetProxy().DecrBy(ctx, key, decrement)
157
}
func instance.Expire
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

58
func (i *instance) Expire(ctx context.Context, key string, expiration time.Duration) *rdsDrv.BoolCmd {
59
        return i.GetProxy().Expire(ctx, key, expiration)
60
}
func instance.GetRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

161
func (i *instance) GetRange(ctx context.Context, key string, start, end int64) *rdsDrv.StringCmd {
162
        return i.GetProxy().GetRange(ctx, key, start, end)
163
}
func instance.GetSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

164
func (i *instance) GetSet(ctx context.Context, key string, value any) *rdsDrv.StringCmd {
165
        return i.GetProxy().GetSet(ctx, key, value)
166
}
func instance.GetEx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

167
func (i *instance) GetEx(ctx context.Context, key string, expiration time.Duration) *rdsDrv.StringCmd {
168
        return i.GetProxy().GetEx(ctx, key, expiration)
169
}
func instance.GetDel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

170
func (i *instance) GetDel(ctx context.Context, key string) *rdsDrv.StringCmd {
171
        return i.GetProxy().GetDel(ctx, key)
172
}
func instance.Incr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

173
func (i *instance) Incr(ctx context.Context, key string) *rdsDrv.IntCmd {
174
        return i.GetProxy().Incr(ctx, key)
175
}
func instance.IncrBy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

176
func (i *instance) IncrBy(ctx context.Context, key string, value int64) *rdsDrv.IntCmd {
177
        return i.GetProxy().IncrBy(ctx, key, value)
178
}
func instance.IncrByFloat
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

179
func (i *instance) IncrByFloat(ctx context.Context, key string, value float64) *rdsDrv.FloatCmd {
180
        return i.GetProxy().IncrByFloat(ctx, key, value)
181
}
func instance.Exists
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

55
func (i *instance) Exists(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
56
        return i.GetProxy().Exists(ctx, keys...)
57
}
func instance.MSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

185
func (i *instance) MSet(ctx context.Context, values ...any) *rdsDrv.StatusCmd {
186
        return i.GetProxy().MSet(ctx, values...)
187
}
func instance.MSetNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

188
func (i *instance) MSetNX(ctx context.Context, values ...any) *rdsDrv.BoolCmd {
189
        return i.GetProxy().MSetNX(ctx, values...)
190
}
func instance.Dump
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

52
func (i *instance) Dump(ctx context.Context, key string) *rdsDrv.StringCmd {
53
        return i.GetProxy().Dump(ctx, key)
54
}
func instance.SetArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

194
func (i *instance) SetArgs(ctx context.Context, key string, value any, a rdsDrv.SetArgs) *rdsDrv.StatusCmd {
195
        return i.GetProxy().SetArgs(ctx, key, value, a)
196
}
func instance.SetEx
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

197
func (i *instance) SetEx(ctx context.Context, key string, value any,
198
        expiration time.Duration) *rdsDrv.StatusCmd {
199
        return i.GetProxy().SetEx(ctx, key, value, expiration)
200
}
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

49
func (i *instance) Unlink(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
50
        return i.GetProxy().Unlink(ctx, keys...)
51
}
func instance.SetXX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

204
func (i *instance) SetXX(ctx context.Context, key string, value any, expiration time.Duration) *rdsDrv.BoolCmd {
205
        return i.GetProxy().SetXX(ctx, key, value, expiration)
206
}
func instance.SetRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

207
func (i *instance) SetRange(ctx context.Context, key string, offset int64, value string) *rdsDrv.IntCmd {
208
        return i.GetProxy().SetRange(ctx, key, offset, value)
209
}
func instance.StrLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

210
func (i *instance) StrLen(ctx context.Context, key string) *rdsDrv.IntCmd {
211
        return i.GetProxy().StrLen(ctx, key)
212
}
func instance.Copy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

213
func (i *instance) Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *rdsDrv.IntCmd {
214
        return i.GetProxy().Copy(ctx, sourceKey, destKey, db, replace)
215
}
func instance.GetBit
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

216
func (i *instance) GetBit(ctx context.Context, key string, offset int64) *rdsDrv.IntCmd {
217
        return i.GetProxy().GetBit(ctx, key, offset)
218
}
func instance.SetBit
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

219
func (i *instance) SetBit(ctx context.Context, key string, offset int64, value int) *rdsDrv.IntCmd {
220
        return i.GetProxy().SetBit(ctx, key, offset, value)
221
}
func instance.BitCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

222
func (i *instance) BitCount(ctx context.Context, key string, bitCount *rdsDrv.BitCount) *rdsDrv.IntCmd {
223
        return i.GetProxy().BitCount(ctx, key, bitCount)
224
}
func instance.BitOpAnd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

225
func (i *instance) BitOpAnd(ctx context.Context, destKey string, keys ...string) *rdsDrv.IntCmd {
226
        return i.GetProxy().BitOpAnd(ctx, destKey, keys...)
227
}
func instance.BitOpOr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

228
func (i *instance) BitOpOr(ctx context.Context, destKey string, keys ...string) *rdsDrv.IntCmd {
229
        return i.GetProxy().BitOpOr(ctx, destKey, keys...)
230
}
func instance.BitOpXor
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

231
func (i *instance) BitOpXor(ctx context.Context, destKey string, keys ...string) *rdsDrv.IntCmd {
232
        return i.GetProxy().BitOpXor(ctx, destKey, keys...)
233
}
func instance.BitOpNot
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

234
func (i *instance) BitOpNot(ctx context.Context, destKey string, key string) *rdsDrv.IntCmd {
235
        return i.GetProxy().BitOpNot(ctx, destKey, key)
236
}
func instance.BitPos
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

237
func (i *instance) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *rdsDrv.IntCmd {
238
        return i.GetProxy().BitPos(ctx, key, bit, pos...)
239
}
func instance.BitPosSpan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

240
func (i *instance) BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *rdsDrv.IntCmd {
241
        return i.GetProxy().BitPosSpan(ctx, key, bit, start, end, span)
242
}
func instance.BitField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

243
func (i *instance) BitField(ctx context.Context, key string, args ...any) *rdsDrv.IntSliceCmd {
244
        return i.GetProxy().BitField(ctx, key, args...)
245
}
func instance.Scan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

246
func (i *instance) Scan(ctx context.Context, cursor uint64, match string, count int64) *rdsDrv.ScanCmd {
247
        return i.GetProxy().Scan(ctx, cursor, match, count)
248
}
func instance.ScanType
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

249
func (i *instance) ScanType(ctx context.Context, cursor uint64, match string, count int64,
250
        keyType string) *rdsDrv.ScanCmd {
251
        return i.GetProxy().ScanType(ctx, cursor, match, count, keyType)
252
}
func instance.SScan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

253
func (i *instance) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *rdsDrv.ScanCmd {
254
        return i.GetProxy().SScan(ctx, key, cursor, match, count)
255
}
func instance.HScan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

256
func (i *instance) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *rdsDrv.ScanCmd {
257
        return i.GetProxy().HScan(ctx, key, cursor, match, count)
258
}
func instance.ZScan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

259
func (i *instance) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *rdsDrv.ScanCmd {
260
        return i.GetProxy().ZScan(ctx, key, cursor, match, count)
261
}
func instance.HDel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

262
func (i *instance) HDel(ctx context.Context, key string, fields ...string) *rdsDrv.IntCmd {
263
        return i.GetProxy().HDel(ctx, key, fields...)
264
}
func instance.HExists
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

265
func (i *instance) HExists(ctx context.Context, key, field string) *rdsDrv.BoolCmd {
266
        return i.GetProxy().HExists(ctx, key, field)
267
}
func instance.HGet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

268
func (i *instance) HGet(ctx context.Context, key, field string) *rdsDrv.StringCmd {
269
        return i.GetProxy().HGet(ctx, key, field)
270
}
func instance.HGetAll
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

271
func (i *instance) HGetAll(ctx context.Context, key string) *rdsDrv.MapStringStringCmd {
272
        return i.GetProxy().HGetAll(ctx, key)
273
}
func instance.HIncrBy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

274
func (i *instance) HIncrBy(ctx context.Context, key, field string, incr int64) *rdsDrv.IntCmd {
275
        return i.GetProxy().HIncrBy(ctx, key, field, incr)
276
}
func instance.HIncrByFloat
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

277
func (i *instance) HIncrByFloat(ctx context.Context, key, field string, incr float64) *rdsDrv.FloatCmd {
278
        return i.GetProxy().HIncrByFloat(ctx, key, field, incr)
279
}
func instance.HKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

280
func (i *instance) HKeys(ctx context.Context, key string) *rdsDrv.StringSliceCmd {
281
        return i.GetProxy().HKeys(ctx, key)
282
}
func instance.HLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

283
func (i *instance) HLen(ctx context.Context, key string) *rdsDrv.IntCmd {
284
        return i.GetProxy().HLen(ctx, key)
285
}
func instance.HMGet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

286
func (i *instance) HMGet(ctx context.Context, key string, fields ...string) *rdsDrv.SliceCmd {
287
        return i.GetProxy().HMGet(ctx, key, fields...)
288
}
func instance.HSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

289
func (i *instance) HSet(ctx context.Context, key string, values ...any) *rdsDrv.IntCmd {
290
        return i.GetProxy().HSet(ctx, key, values...)
291
}
func instance.HMSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

292
func (i *instance) HMSet(ctx context.Context, key string, values ...any) *rdsDrv.BoolCmd {
293
        return i.GetProxy().HMSet(ctx, key, values...)
294
}
func instance.HSetNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

295
func (i *instance) HSetNX(ctx context.Context, key, field string, value any) *rdsDrv.BoolCmd {
296
        return i.GetProxy().HSetNX(ctx, key, field, value)
297
}
func instance.HVals
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

298
func (i *instance) HVals(ctx context.Context, key string) *rdsDrv.StringSliceCmd {
299
        return i.GetProxy().HVals(ctx, key)
300
}
func instance.HRandField
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

301
func (i *instance) HRandField(ctx context.Context, key string, count int) *rdsDrv.StringSliceCmd {
302
        return i.GetProxy().HRandField(ctx, key, count)
303
}
func instance.HRandFieldWithValues
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

304
func (i *instance) HRandFieldWithValues(ctx context.Context, key string, count int) *rdsDrv.KeyValueSliceCmd {
305
        return i.GetProxy().HRandFieldWithValues(ctx, key, count)
306
}
func instance.BLPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

307
func (i *instance) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *rdsDrv.StringSliceCmd {
308
        return i.GetProxy().BLPop(ctx, timeout, keys...)
309
}
func instance.BLMPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

310
func (i *instance) BLMPop(ctx context.Context, timeout time.Duration, direction string,
311
        count int64, keys ...string) *rdsDrv.KeyValuesCmd {
312
        return i.GetProxy().BLMPop(ctx, timeout, direction, count, keys...)
313
}
func instance.BRPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

314
func (i *instance) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *rdsDrv.StringSliceCmd {
315
        return i.GetProxy().BRPop(ctx, timeout, keys...)
316
}
func instance.BRPopLPush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

317
func (i *instance) BRPopLPush(ctx context.Context, source, destination string,
318
        timeout time.Duration) *rdsDrv.StringCmd {
319
        return i.GetProxy().BRPopLPush(ctx, source, destination, timeout)
320
}
func instance.LCS
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

321
func (i *instance) LCS(ctx context.Context, q *rdsDrv.LCSQuery) *rdsDrv.LCSCmd {
322
        return i.GetProxy().LCS(ctx, q)
323
}
func instance.LIndex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

324
func (i *instance) LIndex(ctx context.Context, key string, index int64) *rdsDrv.StringCmd {
325
        return i.GetProxy().LIndex(ctx, key, index)
326
}
func instance.LMPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

327
func (i *instance) LMPop(ctx context.Context, direction string, count int64, keys ...string) *rdsDrv.KeyValuesCmd {
328
        return i.GetProxy().LMPop(ctx, direction, count, keys...)
329
}
func instance.LInsert
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

330
func (i *instance) LInsert(ctx context.Context, key, op string, pivot, value any) *rdsDrv.IntCmd {
331
        return i.GetProxy().LInsert(ctx, key, op, pivot, value)
332
}
func instance.LInsertBefore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

333
func (i *instance) LInsertBefore(ctx context.Context, key string, pivot, value any) *rdsDrv.IntCmd {
334
        return i.GetProxy().LInsertBefore(ctx, key, pivot, value)
335
}
func instance.LInsertAfter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

336
func (i *instance) LInsertAfter(ctx context.Context, key string, pivot, value any) *rdsDrv.IntCmd {
337
        return i.GetProxy().LInsertAfter(ctx, key, pivot, value)
338
}
func instance.LLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

339
func (i *instance) LLen(ctx context.Context, key string) *rdsDrv.IntCmd {
340
        return i.GetProxy().LLen(ctx, key)
341
}
func instance.LPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

342
func (i *instance) LPop(ctx context.Context, key string) *rdsDrv.StringCmd {
343
        return i.GetProxy().LPop(ctx, key)
344
}
func instance.LPopCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

345
func (i *instance) LPopCount(ctx context.Context, key string, count int) *rdsDrv.StringSliceCmd {
346
        return i.GetProxy().LPopCount(ctx, key, count)
347
}
func instance.LPos
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

348
func (i *instance) LPos(ctx context.Context, key string, value string, args rdsDrv.LPosArgs) *rdsDrv.IntCmd {
349
        return i.GetProxy().LPos(ctx, key, value, args)
350
}
func instance.LPosCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

351
func (i *instance) LPosCount(ctx context.Context, key string, value string, count int64,
352
        args rdsDrv.LPosArgs) *rdsDrv.IntSliceCmd {
353
        return i.GetProxy().LPosCount(ctx, key, value, count, args)
354
}
func instance.LPush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

355
func (i *instance) LPush(ctx context.Context, key string, values ...any) *rdsDrv.IntCmd {
356
        return i.GetProxy().LPush(ctx, key, values...)
357
}
func instance.LPushX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

358
func (i *instance) LPushX(ctx context.Context, key string, values ...any) *rdsDrv.IntCmd {
359
        return i.GetProxy().LPushX(ctx, key, values...)
360
}
func instance.LRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

361
func (i *instance) LRange(ctx context.Context, key string, start, stop int64) *rdsDrv.StringSliceCmd {
362
        return i.GetProxy().LRange(ctx, key, start, stop)
363
}
func instance.LRem
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

364
func (i *instance) LRem(ctx context.Context, key string, count int64, value any) *rdsDrv.IntCmd {
365
        return i.GetProxy().LRem(ctx, key, count, value)
366
}
func instance.LSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

367
func (i *instance) LSet(ctx context.Context, key string, index int64, value any) *rdsDrv.StatusCmd {
368
        return i.GetProxy().LSet(ctx, key, index, value)
369
}
func instance.Quit
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

43
func (i *instance) Quit(ctx context.Context) *rdsDrv.StatusCmd {
44
        return i.GetProxy().Quit(ctx)
45
}
func instance.RPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

373
func (i *instance) RPop(ctx context.Context, key string) *rdsDrv.StringCmd {
374
        return i.GetProxy().RPop(ctx, key)
375
}
func instance.RPopCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

376
func (i *instance) RPopCount(ctx context.Context, key string, count int) *rdsDrv.StringSliceCmd {
377
        return i.GetProxy().RPopCount(ctx, key, count)
378
}
func instance.RPopLPush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

379
func (i *instance) RPopLPush(ctx context.Context, source, destination string) *rdsDrv.StringCmd {
380
        return i.GetProxy().RPopLPush(ctx, source, destination)
381
}
func instance.RPush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

382
func (i *instance) RPush(ctx context.Context, key string, values ...any) *rdsDrv.IntCmd {
383
        return i.GetProxy().RPush(ctx, key, values...)
384
}
func instance.RPushX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

385
func (i *instance) RPushX(ctx context.Context, key string, values ...any) *rdsDrv.IntCmd {
386
        return i.GetProxy().RPushX(ctx, key, values...)
387
}
func instance.LMove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

388
func (i *instance) LMove(ctx context.Context, source, destination, srcpos, destpos string) *rdsDrv.StringCmd {
389
        return i.GetProxy().LMove(ctx, source, destination, srcpos, destpos)
390
}
func instance.BLMove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

391
func (i *instance) BLMove(ctx context.Context, source, destination, srcpos, destpos string,
392
        timeout time.Duration) *rdsDrv.StringCmd {
393
        return i.GetProxy().BLMove(ctx, source, destination, srcpos, destpos, timeout)
394
}
func instance.Ping
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

40
func (i *instance) Ping(ctx context.Context) *rdsDrv.StatusCmd {
41
        return i.GetProxy().Ping(ctx)
42
}
func instance.SCard
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

398
func (i *instance) SCard(ctx context.Context, key string) *rdsDrv.IntCmd {
399
        return i.GetProxy().SCard(ctx, key)
400
}
func instance.SDiff
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

401
func (i *instance) SDiff(ctx context.Context, keys ...string) *rdsDrv.StringSliceCmd {
402
        return i.GetProxy().SDiff(ctx, keys...)
403
}
func instance.SDiffStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

404
func (i *instance) SDiffStore(ctx context.Context, destination string, keys ...string) *rdsDrv.IntCmd {
405
        return i.GetProxy().SDiffStore(ctx, destination, keys...)
406
}
func instance.SInter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

407
func (i *instance) SInter(ctx context.Context, keys ...string) *rdsDrv.StringSliceCmd {
408
        return i.GetProxy().SInter(ctx, keys...)
409
}
func instance.SInterCard
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

410
func (i *instance) SInterCard(ctx context.Context, limit int64, keys ...string) *rdsDrv.IntCmd {
411
        return i.GetProxy().SInterCard(ctx, limit, keys...)
412
}
func instance.SInterStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

413
func (i *instance) SInterStore(ctx context.Context, destination string, keys ...string) *rdsDrv.IntCmd {
414
        return i.GetProxy().SInterStore(ctx, destination, keys...)
415
}
func instance.SIsMember
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

416
func (i *instance) SIsMember(ctx context.Context, key string, member any) *rdsDrv.BoolCmd {
417
        return i.GetProxy().SIsMember(ctx, key, member)
418
}
func instance.SMIsMember
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

419
func (i *instance) SMIsMember(ctx context.Context, key string, members ...any) *rdsDrv.BoolSliceCmd {
420
        return i.GetProxy().SMIsMember(ctx, key, members...)
421
}
func instance.SMembers
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

422
func (i *instance) SMembers(ctx context.Context, key string) *rdsDrv.StringSliceCmd {
423
        return i.GetProxy().SMembers(ctx, key)
424
}
func instance.SMembersMap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

425
func (i *instance) SMembersMap(ctx context.Context, key string) *rdsDrv.StringStructMapCmd {
426
        return i.GetProxy().SMembersMap(ctx, key)
427
}
func instance.SMove
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

428
func (i *instance) SMove(ctx context.Context, source, destination string, member any) *rdsDrv.BoolCmd {
429
        return i.GetProxy().SMove(ctx, source, destination, member)
430
}
func instance.SPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

431
func (i *instance) SPop(ctx context.Context, key string) *rdsDrv.StringCmd {
432
        return i.GetProxy().SPop(ctx, key)
433
}
func instance.SPopN
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

434
func (i *instance) SPopN(ctx context.Context, key string, count int64) *rdsDrv.StringSliceCmd {
435
        return i.GetProxy().SPopN(ctx, key, count)
436
}
func instance.SRandMember
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

437
func (i *instance) SRandMember(ctx context.Context, key string) *rdsDrv.StringCmd {
438
        return i.GetProxy().SRandMember(ctx, key)
439
}
func instance.SRandMemberN
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

440
func (i *instance) SRandMemberN(ctx context.Context, key string, count int64) *rdsDrv.StringSliceCmd {
441
        return i.GetProxy().SRandMemberN(ctx, key, count)
442
}
func instance.SRem
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

443
func (i *instance) SRem(ctx context.Context, key string, members ...any) *rdsDrv.IntCmd {
444
        return i.GetProxy().SRem(ctx, key, members...)
445
}
func instance.SUnion
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

446
func (i *instance) SUnion(ctx context.Context, keys ...string) *rdsDrv.StringSliceCmd {
447
        return i.GetProxy().SUnion(ctx, keys...)
448
}
func instance.SUnionStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

449
func (i *instance) SUnionStore(ctx context.Context, destination string, keys ...string) *rdsDrv.IntCmd {
450
        return i.GetProxy().SUnionStore(ctx, destination, keys...)
451
}
func instance.Echo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

37
func (i *instance) Echo(ctx context.Context, message any) *rdsDrv.StringCmd {
38
        return i.GetProxy().Echo(ctx, message)
39
}
func instance.XDel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

455
func (i *instance) XDel(ctx context.Context, stream string, ids ...string) *rdsDrv.IntCmd {
456
        return i.GetProxy().XDel(ctx, stream, ids...)
457
}
func instance.XLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

458
func (i *instance) XLen(ctx context.Context, stream string) *rdsDrv.IntCmd {
459
        return i.GetProxy().XLen(ctx, stream)
460
}
func instance.XRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

461
func (i *instance) XRange(ctx context.Context, stream, start, stop string) *rdsDrv.XMessageSliceCmd {
462
        return i.GetProxy().XRange(ctx, stream, start, stop)
463
}
func instance.XRangeN
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

464
func (i *instance) XRangeN(ctx context.Context, stream, start, stop string, count int64) *rdsDrv.XMessageSliceCmd {
465
        return i.GetProxy().XRangeN(ctx, stream, start, stop, count)
466
}
func instance.XRevRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

467
func (i *instance) XRevRange(ctx context.Context, stream string, start, stop string) *rdsDrv.XMessageSliceCmd {
468
        return i.GetProxy().XRevRange(ctx, stream, start, stop)
469
}
func instance.XRevRangeN
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

470
func (i *instance) XRevRangeN(ctx context.Context, stream string,
471
        start, stop string, count int64) *rdsDrv.XMessageSliceCmd {
472
        return i.GetProxy().XRevRangeN(ctx, stream, start, stop, count)
473
}
func instance.XRead
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

474
func (i *instance) XRead(ctx context.Context, a *rdsDrv.XReadArgs) *rdsDrv.XStreamSliceCmd {
475
        return i.GetProxy().XRead(ctx, a)
476
}
func instance.XReadStreams
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

477
func (i *instance) XReadStreams(ctx context.Context, streams ...string) *rdsDrv.XStreamSliceCmd {
478
        return i.GetProxy().XReadStreams(ctx, streams...)
479
}
func instance.XGroupCreate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

480
func (i *instance) XGroupCreate(ctx context.Context, stream, group, start string) *rdsDrv.StatusCmd {
481
        return i.GetProxy().XGroupCreate(ctx, stream, group, start)
482
}
func instance.ClientGetName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

34
func (i *instance) ClientGetName(ctx context.Context) *rdsDrv.StringCmd {
35
        return i.GetProxy().ClientGetName(ctx)
36
}
func instance.XGroupSetID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

486
func (i *instance) XGroupSetID(ctx context.Context, stream, group, start string) *rdsDrv.StatusCmd {
487
        return i.GetProxy().XGroupSetID(ctx, stream, group, start)
488
}
func instance.XGroupDestroy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

489
func (i *instance) XGroupDestroy(ctx context.Context, stream, group string) *rdsDrv.IntCmd {
490
        return i.GetProxy().XGroupDestroy(ctx, stream, group)
491
}
func instance.XGroupCreateConsumer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

492
func (i *instance) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *rdsDrv.IntCmd {
493
        return i.GetProxy().XGroupCreateConsumer(ctx, stream, group, consumer)
494
}
func instance.XGroupDelConsumer
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

495
func (i *instance) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *rdsDrv.IntCmd {
496
        return i.GetProxy().XGroupDelConsumer(ctx, stream, group, consumer)
497
}
func instance.CommandGetKeysAndFlags
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

31
func (i *instance) CommandGetKeysAndFlags(ctx context.Context, commands ...any) *rdsDrv.KeyFlagsCmd {
32
        return i.GetProxy().CommandGetKeysAndFlags(ctx, commands...)
33
}
func instance.LTrim
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

370
func (i *instance) LTrim(ctx context.Context, key string, start, stop int64) *rdsDrv.StatusCmd {
371
        return i.GetProxy().LTrim(ctx, key, start, stop)
372
}
func instance.XPending
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

504
func (i *instance) XPending(ctx context.Context, stream, group string) *rdsDrv.XPendingCmd {
505
        return i.GetProxy().XPending(ctx, stream, group)
506
}
func instance.CommandGetKeys
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

28
func (i *instance) CommandGetKeys(ctx context.Context, commands ...any) *rdsDrv.StringSliceCmd {
29
        return i.GetProxy().CommandGetKeys(ctx, commands...)
30
}
func instance.CommandList
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

25
func (i *instance) CommandList(ctx context.Context, filter *rdsDrv.FilterBy) *rdsDrv.StringSliceCmd {
26
        return i.GetProxy().CommandList(ctx, filter)
27
}
func instance.XClaimJustID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

513
func (i *instance) XClaimJustID(ctx context.Context, a *rdsDrv.XClaimArgs) *rdsDrv.StringSliceCmd {
514
        return i.GetProxy().XClaimJustID(ctx, a)
515
}
func instance.XAutoClaim
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

516
func (i *instance) XAutoClaim(ctx context.Context, a *rdsDrv.XAutoClaimArgs) *rdsDrv.XAutoClaimCmd {
517
        return i.GetProxy().XAutoClaim(ctx, a)
518
}
func instance.XAutoClaimJustID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

519
func (i *instance) XAutoClaimJustID(ctx context.Context, a *rdsDrv.XAutoClaimArgs) *rdsDrv.XAutoClaimJustIDCmd {
520
        return i.GetProxy().XAutoClaimJustID(ctx, a)
521
}
func instance.XTrimMaxLen
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

522
func (i *instance) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *rdsDrv.IntCmd {
523
        return i.GetProxy().XTrimMaxLen(ctx, key, maxLen)
524
}
func instance.XTrimMaxLenApprox
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

525
func (i *instance) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *rdsDrv.IntCmd {
526
        return i.GetProxy().XTrimMaxLenApprox(ctx, key, maxLen, limit)
527
}
func instance.XTrimMinID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

528
func (i *instance) XTrimMinID(ctx context.Context, key string, minID string) *rdsDrv.IntCmd {
529
        return i.GetProxy().XTrimMinID(ctx, key, minID)
530
}
func instance.XTrimMinIDApprox
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

531
func (i *instance) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *rdsDrv.IntCmd {
532
        return i.GetProxy().XTrimMinIDApprox(ctx, key, minID, limit)
533
}
func instance.XInfoGroups
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

534
func (i *instance) XInfoGroups(ctx context.Context, key string) *rdsDrv.XInfoGroupsCmd {
535
        return i.GetProxy().XInfoGroups(ctx, key)
536
}
func instance.XInfoStream
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

537
func (i *instance) XInfoStream(ctx context.Context, key string) *rdsDrv.XInfoStreamCmd {
538
        return i.GetProxy().XInfoStream(ctx, key)
539
}
func instance.XInfoStreamFull
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

540
func (i *instance) XInfoStreamFull(ctx context.Context, key string, count int) *rdsDrv.XInfoStreamFullCmd {
541
        return i.GetProxy().XInfoStreamFull(ctx, key, count)
542
}
func instance.XInfoConsumers
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

543
func (i *instance) XInfoConsumers(ctx context.Context, key string, group string) *rdsDrv.XInfoConsumersCmd {
544
        return i.GetProxy().XInfoConsumers(ctx, key, group)
545
}
func instance.BZPopMax
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

546
func (i *instance) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *rdsDrv.ZWithKeyCmd {
547
        return i.GetProxy().BZPopMax(ctx, timeout, keys...)
548
}
func instance.BZPopMin
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

549
func (i *instance) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *rdsDrv.ZWithKeyCmd {
550
        return i.GetProxy().BZPopMin(ctx, timeout, keys...)
551
}
func instance.BZMPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

552
func (i *instance) BZMPop(ctx context.Context, timeout time.Duration, order string,
553
        count int64, keys ...string) *rdsDrv.ZSliceWithKeyCmd {
554
        return i.GetProxy().BZMPop(ctx, timeout, order, count, keys...)
555
}
func instance.Command
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

22
func (i *instance) Command(ctx context.Context) *rdsDrv.CommandsInfoCmd {
23
        return i.GetProxy().Command(ctx)
24
}
func instance.ZAddLT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

559
func (i *instance) ZAddLT(ctx context.Context, key string, members ...rdsDrv.Z) *rdsDrv.IntCmd {
560
        return i.GetProxy().ZAddLT(ctx, key, members...)
561
}
func instance.ZAddGT
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

562
func (i *instance) ZAddGT(ctx context.Context, key string, members ...rdsDrv.Z) *rdsDrv.IntCmd {
563
        return i.GetProxy().ZAddGT(ctx, key, members...)
564
}
func instance.ZAddNX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

565
func (i *instance) ZAddNX(ctx context.Context, key string, members ...rdsDrv.Z) *rdsDrv.IntCmd {
566
        return i.GetProxy().ZAddNX(ctx, key, members...)
567
}
func instance.ZAddXX
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

568
func (i *instance) ZAddXX(ctx context.Context, key string, members ...rdsDrv.Z) *rdsDrv.IntCmd {
569
        return i.GetProxy().ZAddXX(ctx, key, members...)
570
}
func instance.ZAddArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

571
func (i *instance) ZAddArgs(ctx context.Context, key string, args rdsDrv.ZAddArgs) *rdsDrv.IntCmd {
572
        return i.GetProxy().ZAddArgs(ctx, key, args)
573
}
func instance.ZAddArgsIncr
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

574
func (i *instance) ZAddArgsIncr(ctx context.Context, key string, args rdsDrv.ZAddArgs) *rdsDrv.FloatCmd {
575
        return i.GetProxy().ZAddArgsIncr(ctx, key, args)
576
}
func instance.ZCard
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

577
func (i *instance) ZCard(ctx context.Context, key string) *rdsDrv.IntCmd {
578
        return i.GetProxy().ZCard(ctx, key)
579
}
func instance.ZCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

580
func (i *instance) ZCount(ctx context.Context, key, min, max string) *rdsDrv.IntCmd {
581
        return i.GetProxy().ZCount(ctx, key, min, max)
582
}
func instance.ZLexCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

583
func (i *instance) ZLexCount(ctx context.Context, key, min, max string) *rdsDrv.IntCmd {
584
        return i.GetProxy().ZLexCount(ctx, key, min, max)
585
}
func instance.ZIncrBy
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

586
func (i *instance) ZIncrBy(ctx context.Context, key string, increment float64, member string) *rdsDrv.FloatCmd {
587
        return i.GetProxy().ZIncrBy(ctx, key, increment, member)
588
}
func instance.ZInter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

589
func (i *instance) ZInter(ctx context.Context, store *rdsDrv.ZStore) *rdsDrv.StringSliceCmd {
590
        return i.GetProxy().ZInter(ctx, store)
591
}
func instance.ZInterWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

592
func (i *instance) ZInterWithScores(ctx context.Context, store *rdsDrv.ZStore) *rdsDrv.ZSliceCmd {
593
        return i.GetProxy().ZInterWithScores(ctx, store)
594
}
func instance.ZInterCard
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

595
func (i *instance) ZInterCard(ctx context.Context, limit int64, keys ...string) *rdsDrv.IntCmd {
596
        return i.GetProxy().ZInterCard(ctx, limit, keys...)
597
}
func instance.ZInterStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

598
func (i *instance) ZInterStore(ctx context.Context, destination string, store *rdsDrv.ZStore) *rdsDrv.IntCmd {
599
        return i.GetProxy().ZInterStore(ctx, destination, store)
600
}
func instance.ZMPop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

601
func (i *instance) ZMPop(ctx context.Context, order string, count int64, keys ...string) *rdsDrv.ZSliceWithKeyCmd {
602
        return i.GetProxy().ZMPop(ctx, order, count, keys...)
603
}
func instance.ZMScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

604
func (i *instance) ZMScore(ctx context.Context, key string, members ...string) *rdsDrv.FloatSliceCmd {
605
        return i.GetProxy().ZMScore(ctx, key, members...)
606
}
func instance.ZPopMax
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

607
func (i *instance) ZPopMax(ctx context.Context, key string, count ...int64) *rdsDrv.ZSliceCmd {
608
        return i.GetProxy().ZPopMax(ctx, key, count...)
609
}
func instance.ZPopMin
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

610
func (i *instance) ZPopMin(ctx context.Context, key string, count ...int64) *rdsDrv.ZSliceCmd {
611
        return i.GetProxy().ZPopMin(ctx, key, count...)
612
}
func instance.ZRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

613
func (i *instance) ZRange(ctx context.Context, key string, start, stop int64) *rdsDrv.StringSliceCmd {
614
        return i.GetProxy().ZRange(ctx, key, start, stop)
615
}
func instance.ZRangeWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

616
func (i *instance) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *rdsDrv.ZSliceCmd {
617
        return i.GetProxy().ZRangeWithScores(ctx, key, start, stop)
618
}
func instance.ZRangeByScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

619
func (i *instance) ZRangeByScore(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.StringSliceCmd {
620
        return i.GetProxy().ZRangeByScore(ctx, key, opt)
621
}
func instance.ZRangeByLex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

622
func (i *instance) ZRangeByLex(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.StringSliceCmd {
623
        return i.GetProxy().ZRangeByLex(ctx, key, opt)
624
}
func instance.ZRangeByScoreWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

625
func (i *instance) ZRangeByScoreWithScores(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.ZSliceCmd {
626
        return i.GetProxy().ZRangeByScoreWithScores(ctx, key, opt)
627
}
func instance.ZRangeArgs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

628
func (i *instance) ZRangeArgs(ctx context.Context, z rdsDrv.ZRangeArgs) *rdsDrv.StringSliceCmd {
629
        return i.GetProxy().ZRangeArgs(ctx, z)
630
}
func instance.ZRangeArgsWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

631
func (i *instance) ZRangeArgsWithScores(ctx context.Context, z rdsDrv.ZRangeArgs) *rdsDrv.ZSliceCmd {
632
        return i.GetProxy().ZRangeArgsWithScores(ctx, z)
633
}
func instance.ZRangeStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

634
func (i *instance) ZRangeStore(ctx context.Context, dst string, z rdsDrv.ZRangeArgs) *rdsDrv.IntCmd {
635
        return i.GetProxy().ZRangeStore(ctx, dst, z)
636
}
func instance.ZRank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

637
func (i *instance) ZRank(ctx context.Context, key, member string) *rdsDrv.IntCmd {
638
        return i.GetProxy().ZRank(ctx, key, member)
639
}
func instance.ZRankWithScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

640
func (i *instance) ZRankWithScore(ctx context.Context, key, member string) *rdsDrv.RankWithScoreCmd {
641
        return i.GetProxy().ZRankWithScore(ctx, key, member)
642
}
func instance.TxPipeline
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

19
func (i *instance) TxPipeline() rdsDrv.Pipeliner {
20
        return i.GetProxy().TxPipeline()
21
}
func instance.ZRemRangeByRank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

647
func (i *instance) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *rdsDrv.IntCmd {
648
        return i.GetProxy().ZRemRangeByRank(ctx, key, start, stop)
649
}
func instance.ZRemRangeByScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

650
func (i *instance) ZRemRangeByScore(ctx context.Context, key, min, max string) *rdsDrv.IntCmd {
651
        return i.GetProxy().ZRemRangeByScore(ctx, key, min, max)
652
}
func instance.ZRemRangeByLex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

653
func (i *instance) ZRemRangeByLex(ctx context.Context, key, min, max string) *rdsDrv.IntCmd {
654
        return i.GetProxy().ZRemRangeByLex(ctx, key, min, max)
655
}
func instance.ZRevRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

656
func (i *instance) ZRevRange(ctx context.Context, key string, start, stop int64) *rdsDrv.StringSliceCmd {
657
        return i.GetProxy().ZRevRange(ctx, key, start, stop)
658
}
func instance.ZRevRangeWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

659
func (i *instance) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *rdsDrv.ZSliceCmd {
660
        return i.GetProxy().ZRevRangeWithScores(ctx, key, start, stop)
661
}
func instance.ZRevRangeByScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

662
func (i *instance) ZRevRangeByScore(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.StringSliceCmd {
663
        return i.GetProxy().ZRevRangeByScore(ctx, key, opt)
664
}
func instance.ZRevRangeByLex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

665
func (i *instance) ZRevRangeByLex(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.StringSliceCmd {
666
        return i.GetProxy().ZRevRangeByLex(ctx, key, opt)
667
}
func instance.ZRevRangeByScoreWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

668
func (i *instance) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *rdsDrv.ZRangeBy) *rdsDrv.ZSliceCmd {
669
        return i.GetProxy().ZRevRangeByScoreWithScores(ctx, key, opt)
670
}
func instance.ZRevRank
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

671
func (i *instance) ZRevRank(ctx context.Context, key, member string) *rdsDrv.IntCmd {
672
        return i.GetProxy().ZRevRank(ctx, key, member)
673
}
func instance.ZRevRankWithScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

674
func (i *instance) ZRevRankWithScore(ctx context.Context, key, member string) *rdsDrv.RankWithScoreCmd {
675
        return i.GetProxy().ZRevRankWithScore(ctx, key, member)
676
}
func instance.ZScore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

677
func (i *instance) ZScore(ctx context.Context, key, member string) *rdsDrv.FloatCmd {
678
        return i.GetProxy().ZScore(ctx, key, member)
679
}
func instance.ZUnionStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

680
func (i *instance) ZUnionStore(ctx context.Context, dest string, store *rdsDrv.ZStore) *rdsDrv.IntCmd {
681
        return i.GetProxy().ZUnionStore(ctx, dest, store)
682
}
func instance.ZRandMember
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

683
func (i *instance) ZRandMember(ctx context.Context, key string, count int) *rdsDrv.StringSliceCmd {
684
        return i.GetProxy().ZRandMember(ctx, key, count)
685
}
func instance.ZRandMemberWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

686
func (i *instance) ZRandMemberWithScores(ctx context.Context, key string, count int) *rdsDrv.ZSliceCmd {
687
        return i.GetProxy().ZRandMemberWithScores(ctx, key, count)
688
}
func instance.ZUnion
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

689
func (i *instance) ZUnion(ctx context.Context, store rdsDrv.ZStore) *rdsDrv.StringSliceCmd {
690
        return i.GetProxy().ZUnion(ctx, store)
691
}
func instance.ZUnionWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

692
func (i *instance) ZUnionWithScores(ctx context.Context, store rdsDrv.ZStore) *rdsDrv.ZSliceCmd {
693
        return i.GetProxy().ZUnionWithScores(ctx, store)
694
}
func instance.ZDiff
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

695
func (i *instance) ZDiff(ctx context.Context, keys ...string) *rdsDrv.StringSliceCmd {
696
        return i.GetProxy().ZDiff(ctx, keys...)
697
}
func instance.ZDiffWithScores
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

698
func (i *instance) ZDiffWithScores(ctx context.Context, keys ...string) *rdsDrv.ZSliceCmd {
699
        return i.GetProxy().ZDiffWithScores(ctx, keys...)
700
}
func instance.ZDiffStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

701
func (i *instance) ZDiffStore(ctx context.Context, destination string, keys ...string) *rdsDrv.IntCmd {
702
        return i.GetProxy().ZDiffStore(ctx, destination, keys...)
703
}
func instance.PFAdd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

704
func (i *instance) PFAdd(ctx context.Context, key string, els ...any) *rdsDrv.IntCmd {
705
        return i.GetProxy().PFAdd(ctx, key, els...)
706
}
func instance.PFCount
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

707
func (i *instance) PFCount(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
708
        return i.GetProxy().PFCount(ctx, keys...)
709
}
func instance.PFMerge
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

710
func (i *instance) PFMerge(ctx context.Context, dest string, keys ...string) *rdsDrv.StatusCmd {
711
        return i.GetProxy().PFMerge(ctx, dest, keys...)
712
}
func instance.BgRewriteAOF
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

713
func (i *instance) BgRewriteAOF(ctx context.Context) *rdsDrv.StatusCmd {
714
        return i.GetProxy().BgRewriteAOF(ctx)
715
}
func instance.BgSave
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

716
func (i *instance) BgSave(ctx context.Context) *rdsDrv.StatusCmd {
717
        return i.GetProxy().BgSave(ctx)
718
}
func instance.ClientKill
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

719
func (i *instance) ClientKill(ctx context.Context, ipPort string) *rdsDrv.StatusCmd {
720
        return i.GetProxy().ClientKill(ctx, ipPort)
721
}
func instance.ClientKillByFilter
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

722
func (i *instance) ClientKillByFilter(ctx context.Context, keys ...string) *rdsDrv.IntCmd {
723
        return i.GetProxy().ClientKillByFilter(ctx, keys...)
724
}
func instance.ClientList
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

725
func (i *instance) ClientList(ctx context.Context) *rdsDrv.StringCmd {
726
        return i.GetProxy().ClientList(ctx)
727
}
func instance.ClientPause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

728
func (i *instance) ClientPause(ctx context.Context, dur time.Duration) *rdsDrv.BoolCmd {
729
        return i.GetProxy().ClientPause(ctx, dur)
730
}
func instance.ClientUnpause
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

731
func (i *instance) ClientUnpause(ctx context.Context) *rdsDrv.BoolCmd {
732
        return i.GetProxy().ClientUnpause(ctx)
733
}
func instance.ClientID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

734
func (i *instance) ClientID(ctx context.Context) *rdsDrv.IntCmd {
735
        return i.GetProxy().ClientID(ctx)
736
}
func instance.ClientUnblock
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

737
func (i *instance) ClientUnblock(ctx context.Context, id int64) *rdsDrv.IntCmd {
738
        return i.GetProxy().ClientUnblock(ctx, id)
739
}
func instance.ClientUnblockWithError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

740
func (i *instance) ClientUnblockWithError(ctx context.Context, id int64) *rdsDrv.IntCmd {
741
        return i.GetProxy().ClientUnblockWithError(ctx, id)
742
}
func instance.ClientInfo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

743
func (i *instance) ClientInfo(ctx context.Context) *rdsDrv.ClientInfoCmd {
744
        return i.GetProxy().ClientInfo(ctx)
745
}
func instance.ConfigGet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

746
func (i *instance) ConfigGet(ctx context.Context, parameter string) *rdsDrv.MapStringStringCmd {
747
        return i.GetProxy().ConfigGet(ctx, parameter)
748
}
func instance.ConfigResetStat
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

749
func (i *instance) ConfigResetStat(ctx context.Context) *rdsDrv.StatusCmd {
750
        return i.GetProxy().ConfigResetStat(ctx)
751
}
func instance.ConfigSet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

752
func (i *instance) ConfigSet(ctx context.Context, parameter, value string) *rdsDrv.StatusCmd {
753
        return i.GetProxy().ConfigSet(ctx, parameter, value)
754
}
func instance.ConfigRewrite
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

755
func (i *instance) ConfigRewrite(ctx context.Context) *rdsDrv.StatusCmd {
756
        return i.GetProxy().ConfigRewrite(ctx)
757
}
func instance.DBSize
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

758
func (i *instance) DBSize(ctx context.Context) *rdsDrv.IntCmd {
759
        return i.GetProxy().DBSize(ctx)
760
}
func instance.FlushAll
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

761
func (i *instance) FlushAll(ctx context.Context) *rdsDrv.StatusCmd {
762
        return i.GetProxy().FlushAll(ctx)
763
}
func instance.FlushAllAsync
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

764
func (i *instance) FlushAllAsync(ctx context.Context) *rdsDrv.StatusCmd {
765
        return i.GetProxy().FlushAllAsync(ctx)
766
}
func instance.FlushDB
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

767
func (i *instance) FlushDB(ctx context.Context) *rdsDrv.StatusCmd {
768
        return i.GetProxy().FlushDB(ctx)
769
}
func instance.FlushDBAsync
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

770
func (i *instance) FlushDBAsync(ctx context.Context) *rdsDrv.StatusCmd {
771
        return i.GetProxy().FlushDBAsync(ctx)
772
}
func instance.Info
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

773
func (i *instance) Info(ctx context.Context, section ...string) *rdsDrv.StringCmd {
774
        return i.GetProxy().Info(ctx, section...)
775
}
func instance.LastSave
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

776
func (i *instance) LastSave(ctx context.Context) *rdsDrv.IntCmd {
777
        return i.GetProxy().LastSave(ctx)
778
}
func instance.Save
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

779
func (i *instance) Save(ctx context.Context) *rdsDrv.StatusCmd {
780
        return i.GetProxy().Save(ctx)
781
}
func instance.Shutdown
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

782
func (i *instance) Shutdown(ctx context.Context) *rdsDrv.StatusCmd {
783
        return i.GetProxy().Shutdown(ctx)
784
}
func instance.ShutdownSave
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

785
func (i *instance) ShutdownSave(ctx context.Context) *rdsDrv.StatusCmd {
786
        return i.GetProxy().ShutdownSave(ctx)
787
}
func instance.ShutdownNoSave
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

788
func (i *instance) ShutdownNoSave(ctx context.Context) *rdsDrv.StatusCmd {
789
        return i.GetProxy().ShutdownNoSave(ctx)
790
}
func instance.SlaveOf
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

791
func (i *instance) SlaveOf(ctx context.Context, host, port string) *rdsDrv.StatusCmd {
792
        return i.GetProxy().SlaveOf(ctx, host, port)
793
}
func instance.SlowLogGet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

794
func (i *instance) SlowLogGet(ctx context.Context, num int64) *rdsDrv.SlowLogCmd {
795
        return i.GetProxy().SlowLogGet(ctx, num)
796
}
func instance.Time
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

797
func (i *instance) Time(ctx context.Context) *rdsDrv.TimeCmd { return i.GetProxy().Time(ctx) }
func instance.DebugObject
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

798
func (i *instance) DebugObject(ctx context.Context, key string) *rdsDrv.StringCmd {
799
        return i.GetProxy().DebugObject(ctx, key)
800
}
func instance.ReadOnly
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

801
func (i *instance) ReadOnly(ctx context.Context) *rdsDrv.StatusCmd { return i.GetProxy().ReadOnly(ctx) }
func instance.ReadWrite
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

802
func (i *instance) ReadWrite(ctx context.Context) *rdsDrv.StatusCmd {
803
        return i.GetProxy().ReadWrite(ctx)
804
}
func instance.MemoryUsage
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

805
func (i *instance) MemoryUsage(ctx context.Context, key string, samples ...int) *rdsDrv.IntCmd {
806
        return i.GetProxy().MemoryUsage(ctx, key, samples...)
807
}
func instance.TxPipelined
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

16
func (i *instance) TxPipelined(ctx context.Context, fn func(rdsDrv.Pipeliner) error) ([]rdsDrv.Cmder, error) {
17
        return i.GetProxy().TxPipelined(ctx, fn)
18
}
func instance.Pipelined
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

13
func (i *instance) Pipelined(ctx context.Context, fn func(rdsDrv.Pipeliner) error) ([]rdsDrv.Cmder, error) {
14
        return i.GetProxy().Pipelined(ctx, fn)
15
}
func instance.EvalRO
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

814
func (i *instance) EvalRO(ctx context.Context, script string, keys []string, args ...any) *rdsDrv.Cmd {
815
        return i.GetProxy().EvalRO(ctx, script, keys, args...)
816
}
func instance.EvalShaRO
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

817
func (i *instance) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...any) *rdsDrv.Cmd {
818
        return i.GetProxy().EvalShaRO(ctx, sha1, keys, args...)
819
}
func instance.ScriptExists
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

820
func (i *instance) ScriptExists(ctx context.Context, hashes ...string) *rdsDrv.BoolSliceCmd {
821
        return i.GetProxy().ScriptExists(ctx, hashes...)
822
}
func instance.ScriptFlush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

823
func (i *instance) ScriptFlush(ctx context.Context) *rdsDrv.StatusCmd {
824
        return i.GetProxy().ScriptFlush(ctx)
825
}
func instance.ScriptKill
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

826
func (i *instance) ScriptKill(ctx context.Context) *rdsDrv.StatusCmd {
827
        return i.GetProxy().ScriptKill(ctx)
828
}
func instance.ScriptLoad
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

829
func (i *instance) ScriptLoad(ctx context.Context, script string) *rdsDrv.StringCmd {
830
        return i.GetProxy().ScriptLoad(ctx, script)
831
}
func instance.FunctionLoad
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

832
func (i *instance) FunctionLoad(ctx context.Context, code string) *rdsDrv.StringCmd {
833
        return i.GetProxy().FunctionLoad(ctx, code)
834
}
func instance.FunctionLoadReplace
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

835
func (i *instance) FunctionLoadReplace(ctx context.Context, code string) *rdsDrv.StringCmd {
836
        return i.GetProxy().FunctionLoadReplace(ctx, code)
837
}
func instance.FunctionDelete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

838
func (i *instance) FunctionDelete(ctx context.Context, libName string) *rdsDrv.StringCmd {
839
        return i.GetProxy().FunctionDelete(ctx, libName)
840
}
func instance.FunctionFlush
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

841
func (i *instance) FunctionFlush(ctx context.Context) *rdsDrv.StringCmd {
842
        return i.GetProxy().FunctionFlush(ctx)
843
}
func instance.FunctionKill
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

844
func (i *instance) FunctionKill(ctx context.Context) *rdsDrv.StringCmd {
845
        return i.GetProxy().FunctionKill(ctx)
846
}
func instance.FunctionFlushAsync
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

847
func (i *instance) FunctionFlushAsync(ctx context.Context) *rdsDrv.StringCmd {
848
        return i.GetProxy().FunctionFlushAsync(ctx)
849
}
func instance.FunctionList
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

850
func (i *instance) FunctionList(ctx context.Context, q rdsDrv.FunctionListQuery) *rdsDrv.FunctionListCmd {
851
        return i.GetProxy().FunctionList(ctx, q)
852
}
func instance.FunctionDump
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

853
func (i *instance) FunctionDump(ctx context.Context) *rdsDrv.StringCmd {
854
        return i.GetProxy().FunctionDump(ctx)
855
}
func instance.FunctionRestore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

856
func (i *instance) FunctionRestore(ctx context.Context, libDump string) *rdsDrv.StringCmd {
857
        return i.GetProxy().FunctionRestore(ctx, libDump)
858
}
func instance.FunctionStats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

859
func (i *instance) FunctionStats(ctx context.Context) *rdsDrv.FunctionStatsCmd {
860
        return i.GetProxy().FunctionStats(ctx)
861
}
func instance.FCall
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

862
func (i *instance) FCall(ctx context.Context, function string, keys []string, args ...any) *rdsDrv.Cmd {
863
        return i.GetProxy().FCall(ctx, function, keys, args...)
864
}
func instance.FCallRo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

865
func (i *instance) FCallRo(ctx context.Context, function string, keys []string, args ...any) *rdsDrv.Cmd {
866
        return i.GetProxy().FCallRo(ctx, function, keys, args...)
867
}
func instance.FCallRO
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

868
func (i *instance) FCallRO(ctx context.Context, function string, keys []string, args ...interface{}) *rdsDrv.Cmd {
869
        return i.GetProxy().FCallRO(ctx, function, keys, args...)
870
}
func instance.Publish
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

871
func (i *instance) Publish(ctx context.Context, channel string, message any) *rdsDrv.IntCmd {
872
        return i.GetProxy().Publish(ctx, channel, message)
873
}
func instance.SPublish
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

874
func (i *instance) SPublish(ctx context.Context, channel string, message any) *rdsDrv.IntCmd {
875
        return i.GetProxy().SPublish(ctx, channel, message)
876
}
func instance.PubSubChannels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

877
func (i *instance) PubSubChannels(ctx context.Context, pattern string) *rdsDrv.StringSliceCmd {
878
        return i.GetProxy().PubSubChannels(ctx, pattern)
879
}
func instance.PubSubNumSub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

880
func (i *instance) PubSubNumSub(ctx context.Context, channels ...string) *rdsDrv.MapStringIntCmd {
881
        return i.GetProxy().PubSubNumSub(ctx, channels...)
882
}
func instance.PubSubNumPat
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

883
func (i *instance) PubSubNumPat(ctx context.Context) *rdsDrv.IntCmd {
884
        return i.GetProxy().PubSubNumPat(ctx)
885
}
func instance.PubSubShardChannels
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

886
func (i *instance) PubSubShardChannels(ctx context.Context, pattern string) *rdsDrv.StringSliceCmd {
887
        return i.GetProxy().PubSubShardChannels(ctx, pattern)
888
}
func instance.PubSubShardNumSub
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

889
func (i *instance) PubSubShardNumSub(ctx context.Context, channels ...string) *rdsDrv.MapStringIntCmd {
890
        return i.GetProxy().PubSubShardNumSub(ctx, channels...)
891
}
func instance.ClusterMyShardID
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

892
func (i *instance) ClusterMyShardID(ctx context.Context) *rdsDrv.StringCmd {
893
        return i.GetProxy().ClusterMyShardID(ctx)
894
}
func instance.ClusterSlots
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

895
func (i *instance) ClusterSlots(ctx context.Context) *rdsDrv.ClusterSlotsCmd {
896
        return i.GetProxy().ClusterSlots(ctx)
897
}
func instance.ClusterShards
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

898
func (i *instance) ClusterShards(ctx context.Context) *rdsDrv.ClusterShardsCmd {
899
        return i.GetProxy().ClusterShards(ctx)
900
}
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

901
func (i *instance) ClusterLinks(ctx context.Context) *rdsDrv.ClusterLinksCmd {
902
        return i.GetProxy().ClusterLinks(ctx)
903
}
func instance.ClusterNodes
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

904
func (i *instance) ClusterNodes(ctx context.Context) *rdsDrv.StringCmd {
905
        return i.GetProxy().ClusterNodes(ctx)
906
}
func instance.ClusterMeet
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

907
func (i *instance) ClusterMeet(ctx context.Context, host, port string) *rdsDrv.StatusCmd {
908
        return i.GetProxy().ClusterMeet(ctx, host, port)
909
}
func instance.ClusterForget
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

910
func (i *instance) ClusterForget(ctx context.Context, nodeID string) *rdsDrv.StatusCmd {
911
        return i.GetProxy().ClusterForget(ctx, nodeID)
912
}
func instance.ClusterReplicate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

913
func (i *instance) ClusterReplicate(ctx context.Context, nodeID string) *rdsDrv.StatusCmd {
914
        return i.GetProxy().ClusterReplicate(ctx, nodeID)
915
}
func instance.ClusterResetSoft
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

916
func (i *instance) ClusterResetSoft(ctx context.Context) *rdsDrv.StatusCmd {
917
        return i.GetProxy().ClusterResetSoft(ctx)
918
}
func instance.ClusterResetHard
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

919
func (i *instance) ClusterResetHard(ctx context.Context) *rdsDrv.StatusCmd {
920
        return i.GetProxy().ClusterResetHard(ctx)
921
}
func instance.ClusterInfo
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

922
func (i *instance) ClusterInfo(ctx context.Context) *rdsDrv.StringCmd {
923
        return i.GetProxy().ClusterInfo(ctx)
924
}
func instance.ClusterKeySlot
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

925
func (i *instance) ClusterKeySlot(ctx context.Context, key string) *rdsDrv.IntCmd {
926
        return i.GetProxy().ClusterKeySlot(ctx, key)
927
}
func instance.ClusterGetKeysInSlot
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

928
func (i *instance) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *rdsDrv.StringSliceCmd {
929
        return i.GetProxy().ClusterGetKeysInSlot(ctx, slot, count)
930
}
func instance.ClusterCountFailureReports
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

931
func (i *instance) ClusterCountFailureReports(ctx context.Context, nodeID string) *rdsDrv.IntCmd {
932
        return i.GetProxy().ClusterCountFailureReports(ctx, nodeID)
933
}
func instance.ClusterCountKeysInSlot
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

934
func (i *instance) ClusterCountKeysInSlot(ctx context.Context, slot int) *rdsDrv.IntCmd {
935
        return i.GetProxy().ClusterCountKeysInSlot(ctx, slot)
936
}
func instance.ClusterDelSlots
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

937
func (i *instance) ClusterDelSlots(ctx context.Context, slots ...int) *rdsDrv.StatusCmd {
938
        return i.GetProxy().ClusterDelSlots(ctx, slots...)
939
}
func instance.ClusterDelSlotsRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

940
func (i *instance) ClusterDelSlotsRange(ctx context.Context, min, max int) *rdsDrv.StatusCmd {
941
        return i.GetProxy().ClusterDelSlotsRange(ctx, min, max)
942
}
func instance.ClusterSaveConfig
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

943
func (i *instance) ClusterSaveConfig(ctx context.Context) *rdsDrv.StatusCmd {
944
        return i.GetProxy().ClusterSaveConfig(ctx)
945
}
func instance.ClusterSlaves
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

946
func (i *instance) ClusterSlaves(ctx context.Context, nodeID string) *rdsDrv.StringSliceCmd {
947
        return i.GetProxy().ClusterSlaves(ctx, nodeID)
948
}
func instance.ClusterFailover
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

949
func (i *instance) ClusterFailover(ctx context.Context) *rdsDrv.StatusCmd {
950
        return i.GetProxy().ClusterFailover(ctx)
951
}
func instance.ClusterAddSlots
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

952
func (i *instance) ClusterAddSlots(ctx context.Context, slots ...int) *rdsDrv.StatusCmd {
953
        return i.GetProxy().ClusterAddSlots(ctx, slots...)
954
}
func instance.ClusterAddSlotsRange
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

955
func (i *instance) ClusterAddSlotsRange(ctx context.Context, min, max int) *rdsDrv.StatusCmd {
956
        return i.GetProxy().ClusterAddSlotsRange(ctx, min, max)
957
}
func instance.GeoAdd
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

958
func (i *instance) GeoAdd(ctx context.Context, key string, geoLocation ...*rdsDrv.GeoLocation) *rdsDrv.IntCmd {
959
        return i.GetProxy().GeoAdd(ctx, key, geoLocation...)
960
}
func instance.GeoPos
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

961
func (i *instance) GeoPos(ctx context.Context, key string, members ...string) *rdsDrv.GeoPosCmd {
962
        return i.GetProxy().GeoPos(ctx, key, members...)
963
}
func instance.GeoRadius
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

964
func (i *instance) GeoRadius(ctx context.Context, key string, longitude, latitude float64,
965
        query *rdsDrv.GeoRadiusQuery) *rdsDrv.GeoLocationCmd {
966
        return i.GetProxy().GeoRadius(ctx, key, longitude, latitude, query)
967
}
func instance.GeoRadiusStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

968
func (i *instance) GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64,
969
        query *rdsDrv.GeoRadiusQuery) *rdsDrv.IntCmd {
970
        return i.GetProxy().GeoRadiusStore(ctx, key, longitude, latitude, query)
971
}
func instance.GeoRadiusByMember
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

972
func (i *instance) GeoRadiusByMember(ctx context.Context, key, member string,
973
        query *rdsDrv.GeoRadiusQuery) *rdsDrv.GeoLocationCmd {
974
        return i.GetProxy().GeoRadiusByMember(ctx, key, member, query)
975
}
func instance.GeoRadiusByMemberStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

976
func (i *instance) GeoRadiusByMemberStore(ctx context.Context, key, member string,
977
        query *rdsDrv.GeoRadiusQuery) *rdsDrv.IntCmd {
978
        return i.GetProxy().GeoRadiusByMemberStore(ctx, key, member, query)
979
}
func instance.GeoSearch
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

980
func (i *instance) GeoSearch(ctx context.Context, key string, q *rdsDrv.GeoSearchQuery) *rdsDrv.StringSliceCmd {
981
        return i.GetProxy().GeoSearch(ctx, key, q)
982
}
func instance.GeoSearchLocation
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

983
func (i *instance) GeoSearchLocation(ctx context.Context, key string,
984
        q *rdsDrv.GeoSearchLocationQuery) *rdsDrv.GeoSearchLocationCmd {
985
        return i.GetProxy().GeoSearchLocation(ctx, key, q)
986
}
func instance.GeoSearchStore
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

987
func (i *instance) GeoSearchStore(ctx context.Context, key, store string,
988
        q *rdsDrv.GeoSearchStoreQuery) *rdsDrv.IntCmd {
989
        return i.GetProxy().GeoSearchStore(ctx, key, store, q)
990
}
func instance.GeoDist
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

991
func (i *instance) GeoDist(ctx context.Context, key string, member1, member2, unit string) *rdsDrv.FloatCmd {
992
        return i.GetProxy().GeoDist(ctx, key, member1, member2, unit)
993
}
func instance.GeoHash
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

994
func (i *instance) GeoHash(ctx context.Context, key string, members ...string) *rdsDrv.StringSliceCmd {
995
        return i.GetProxy().GeoHash(ctx, key, members...)
996
}
func instance.ACLDryRun
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

997
func (i *instance) ACLDryRun(ctx context.Context, username string, command ...any) *rdsDrv.StringCmd {
998
        return i.GetProxy().ACLDryRun(ctx, username, command...)
999
}
func instance.ModuleLoadex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1000
func (i *instance) ModuleLoadex(ctx context.Context, conf *rdsDrv.ModuleLoadexConfig) *rdsDrv.StringCmd {
1001
        return i.GetProxy().ModuleLoadex(ctx, conf)
1002
}
func instance.AddHook
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1003
func (i *instance) AddHook(hk rdsDrv.Hook) {
1004
        i.GetProxy().AddHook(hk)
1005
}
func instance.Watch
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1006
func (i *instance) Watch(ctx context.Context, fn func(*rdsDrv.Tx) error, keys ...string) error {
1007
        return i.GetProxy().Watch(ctx, fn, keys...)
1008
}
func instance.Do
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1009
func (i *instance) Do(ctx context.Context, args ...any) *rdsDrv.Cmd {
1010
        return i.GetProxy().Do(ctx, args...)
1011
}
func instance.Process
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1012
func (i *instance) Process(ctx context.Context, cmd rdsDrv.Cmder) error {
1013
        return i.GetProxy().Process(ctx, cmd)
1014
}
func @83:22
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/construct.go:

83
func() rdsDrv.UniversalClient { return Use(ctx, name, AppName(opt.AppName)) }
func instance.PSubscribe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1018
func (i *instance) PSubscribe(ctx context.Context, channels ...string) *rdsDrv.PubSub {
1019
        return i.GetProxy().PSubscribe(ctx, channels...)
1020
}
func instance.SSubscribe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1021
func (i *instance) SSubscribe(ctx context.Context, channels ...string) *rdsDrv.PubSub {
1022
        return i.GetProxy().SSubscribe(ctx, channels...)
1023
}
func instance.Close
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1024
func (i *instance) Close() error {
1025
        return i.GetProxy().Close()
1026
}
func instance.PoolStats
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/redis/wrap.go:

1027
func (i *instance) PoolStats() *rdsDrv.PoolStats {
1028
        return i.GetProxy().PoolStats()
1029
}
Package Overview: github.com/wfusion/gofusion/routine 48.4%

Please select a function to see what's left for testing.

Construct(...) github.com/wfusion/gofusion/routine/construct.go 100.0% 32/32
startDaemonRoutines(...) github.com/wfusion/gofusion/routine/metrics.go 100.0% 10/10
Promise(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 6/6
addRoutine(...) github.com/wfusion/gofusion/routine/types.go 100.0% 5/5
@91:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 5/5
@53:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 5/5
Loop(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 4/4
@192:8(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 4/4
Future.GetChan(...) github.com/wfusion/gofusion/routine/future.go 100.0% 3/3
@52:10(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 3/3
addPool(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 3/3
NewPromise(...) github.com/wfusion/gofusion/routine/promise.go 100.0% 3/3
@132:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 3/3
@90:10(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 3/3
configs(...) github.com/wfusion/gofusion/routine/construct.go 100.0% 2/2
@240:3(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 2/2
@104:14(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 2/2
Future.OnCancel(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
Future.OnComplete(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
@131:10(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 2/2
Future.OnFailure(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
Future.loadResult(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
Future.loadVal(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
Future.Get(...) github.com/wfusion/gofusion/routine/future.go 100.0% 2/2
@99:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 2/2
@71:15(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 2/2
pool.Release(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 2/2
forSlice(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 2/2
@97:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 2/2
@38:24(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 1/1
@96:9(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 1/1
@319:8(...) github.com/wfusion/gofusion/routine/future.go 100.0% 1/1
WithoutTimeout(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 1/1
@227:9(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 1/1
promise.Resolve(...) github.com/wfusion/gofusion/routine/promise.go 100.0% 1/1
promise.Reject(...) github.com/wfusion/gofusion/routine/promise.go 100.0% 1/1
AppName(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
@116:15(...) github.com/wfusion/gofusion/routine/future.go 100.0% 1/1
@43:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
init(...) github.com/wfusion/gofusion/routine/construct.go 100.0% 1/1
forceSync(...) github.com/wfusion/gofusion/routine/construct.go 100.0% 1/1
@37:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
@80:16(...) github.com/wfusion/gofusion/routine/construct.go 100.0% 1/1
Channel(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
@31:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
WaitGroup(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
@230:15(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 1/1
@229:11(...) github.com/wfusion/gofusion/routine/candy_utils.go 100.0% 1/1
@25:9(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
ignoreRecycled(...) github.com/wfusion/gofusion/routine/pool.go 100.0% 1/1
Args(...) github.com/wfusion/gofusion/routine/candy.go 100.0% 1/1
NewPool(...) github.com/wfusion/gofusion/routine/pool.go 91.7% 11/12
allocate(...) github.com/wfusion/gofusion/routine/pool.go 89.5% 17/19
Future.setResult(...) github.com/wfusion/gofusion/routine/future.go 88.2% 15/17
release(...) github.com/wfusion/gofusion/routine/pool.go 87.5% 14/16
Goc(...) github.com/wfusion/gofusion/routine/candy.go 87.5% 7/8
Go(...) github.com/wfusion/gofusion/routine/candy.go 87.5% 7/8
start(...) github.com/wfusion/gofusion/routine/candy.go 86.7% 13/15
delRoutine(...) github.com/wfusion/gofusion/routine/types.go 83.3% 5/6
@132:6(...) github.com/wfusion/gofusion/routine/candy_utils.go 80.0% 4/5
pool.Submit(...) github.com/wfusion/gofusion/routine/pool.go 80.0% 4/5
@74:9(...) github.com/wfusion/gofusion/routine/construct.go 77.8% 14/18
wrapPromise(...) github.com/wfusion/gofusion/routine/candy.go 75.0% 6/8
validate(...) github.com/wfusion/gofusion/routine/pool.go 75.0% 3/4
Future.IsCancelled(...) github.com/wfusion/gofusion/routine/future.go 75.0% 3/4
Future.addCallback(...) github.com/wfusion/gofusion/routine/future.go 74.1% 20/27
@66:21(...) github.com/wfusion/gofusion/routine/metrics.go 71.1% 32/45
@531:7(...) github.com/wfusion/gofusion/routine/candy.go 66.7% 4/6
metricsRuntime(...) github.com/wfusion/gofusion/routine/metrics.go 66.7% 2/3
execCallback(...) github.com/wfusion/gofusion/routine/candy_utils.go 63.6% 7/11
getAct(...) github.com/wfusion/gofusion/routine/candy_utils.go 50.0% 12/24
@146:15(...) github.com/wfusion/gofusion/routine/candy.go 50.0% 1/2
@133:9(...) github.com/wfusion/gofusion/routine/candy_utils.go 50.0% 1/2
@111:15(...) github.com/wfusion/gofusion/routine/candy.go 50.0% 1/2
@64:14(...) github.com/wfusion/gofusion/routine/candy.go 50.0% 1/2
@209:14(...) github.com/wfusion/gofusion/routine/candy.go 50.0% 1/2
getFutureReturnVal(...) github.com/wfusion/gofusion/routine/candy_utils.go 40.0% 2/5
@293:8(...) github.com/wfusion/gofusion/routine/future.go 33.3% 1/3
@241:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 33.3% 1/3
getError(...) github.com/wfusion/gofusion/routine/candy_utils.go 25.0% 2/8
Future.Pipe(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/35
WhenAnyMatched(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/26
@341:6(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/24
WhenAll(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/17
AggregateError.Error(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/14
newErrorWithStacks(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/11
whenAllFuture(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/10
@233:9(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/8
Future.GetOrTimeout(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/7
WrapFuture(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/7
showRoutine(...) github.com/wfusion/gofusion/routine/types.go 0.0% 0/6
Future.SetTimeout(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/5
@452:6(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/4
@462:18(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/4
NoMatchedError.HasError(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/4
Loopc(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/4
@472:17(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/3
@160:9(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/3
pipe.getPipe(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/3
@457:17(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/3
startPipe(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/3
@309:5(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/3
@326:8(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/3
@210:11(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/3
@444:19(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/3
@107:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/2
Future.OnSuccess(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/2
promise.OnSuccess(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/2
@209:4(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/2
@312:16(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@106:5(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/2
promise.OnComplete(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/2
promise.OnFailure(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/2
promise.OnCancel(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/2
@159:10(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@221:18(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/2
@361:20(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
writeStrings(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/2
pool.ReleaseTimeout(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/2
@234:18(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/2
@315:17(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@169:14(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@176:15(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@104:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/2
@318:16(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@342:10(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@139:14(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@202:13(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/2
@228:18(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@110:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
@182:15(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
canceller.Cancel(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
pool.Running(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
pool.Free(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
pool.Waiting(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
pool.Cap(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
pool.IsClosed(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
@184:16(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
@233:12(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@101:10(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
@227:12(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@220:12(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
ignoreMutex(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
@102:9(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
@215:18(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
newAggregateError1(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
@214:12(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
newNoMatchedError1(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
Timeout(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
@221:9(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
newNoMatchedError(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
@210:12(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
Options(...) github.com/wfusion/gofusion/routine/pool.go 0.0% 0/1
WhenAny(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
CancelledError.Error(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/1
promise.Cancel(...) github.com/wfusion/gofusion/routine/promise.go 0.0% 0/1
@286:15(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
NoMatchedError.Error(...) github.com/wfusion/gofusion/routine/candy_utils.go 0.0% 0/1
Future.Cancel(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@118:14(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@362:14(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
Future.Canceller(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
canceller.IsCancelled(...) github.com/wfusion/gofusion/routine/future.go 0.0% 0/1
@313:11(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
@316:11(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
@319:11(...) github.com/wfusion/gofusion/routine/candy.go 0.0% 0/1
func Construct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

26
func Construct(ctx context.Context, conf Conf, opts ...utils.OptionExtender) func() {
27
        opt := utils.ApplyOptions[config.InitOption](opts...)
28
        optU := utils.ApplyOptions[candyOption](opts...)
29
        if opt.AppName == "" {
30
                opt.AppName = optU.appName
31
        }
32
33
        if conf.MaxRoutineAmount <= 0 {
34
                conf.MaxRoutineAmount = defaultMaxPoolSize
35
        }
36
37
        rwlock.Lock()
38
        defer rwlock.Unlock()
39
        if pools == nil {
40
                pools = make(map[string]map[string]Pool)
41
        }
42
        if pools[opt.AppName] == nil {
43
                pools[opt.AppName] = make(map[string]Pool)
44
        }
45
        if ignored == nil {
46
                ignored = make(map[string]*atomic.Int64)
47
        }
48
        if ignored[opt.AppName] == nil {
49
                ignored[opt.AppName] = atomic.NewInt64(0)
50
        }
51
        if idle == nil {
52
                idle = make(map[string]*atomic.Int64)
53
        }
54
        if idle[opt.AppName] == nil {
55
                idle[opt.AppName] = atomic.NewInt64(int64(conf.MaxRoutineAmount))
56
        }
57
        if utils.IsStrNotBlank(conf.Logger) {
58
                if defaultLogger == nil {
59
                        defaultLogger = make(map[string]ants.Logger)
60
                }
61
                if defaultLogger[opt.AppName] == nil {
62
                        logger := reflect.New(inspect.TypeOf(conf.Logger)).Interface().(ants.Logger)
63
                        defaultLogger[opt.AppName] = logger
64
                        if custom, ok := logger.(customLogger); ok {
65
                                l := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName))
66
                                custom.Init(l, opt.AppName)
67
                        }
68
                }
69
        }
70
        maxReleaseTime := utils.Must(time.ParseDuration(conf.MaxReleaseTimePerPool))
71
72
        go startDaemonRoutines(ctx, opt.AppName, &conf)
73
74
        return func() {
75
                rwlock.Lock()
76
                defer rwlock.Unlock()
77
78
                pid := syscall.Getpid()
79
                app := config.Use(opt.AppName).AppName()
80
                allExited := func() bool {
81
                        return idle[opt.AppName].Load() == int64(conf.MaxRoutineAmount)-ignored[opt.AppName].Load()
82
                }
83
84
                // waiting for pool
85
                if pools != nil {
86
                        for name, pool := range pools[opt.AppName] {
87
                                if err := pool.ReleaseTimeout(maxReleaseTime, ignoreMutex()); err != nil {
88
                                        log.Printf("%v [Gofusion] %s %s exit with releasing pool %s failed because %s",
89
                                                pid, app, config.ComponentGoroutinePool, name, err)
90
                                }
91
                                delete(pools[opt.AppName], name)
92
                        }
93
                }
94
95
                log.Printf("%v [Gofusion] %s %s pool routines are recycled", pid, app, config.ComponentGoroutinePool)
96
97
                // waiting for go
98
                utils.Timeout(maxReleaseTime, utils.TimeoutWg(&wg))
99
                log.Printf("%v [Gofusion] %s %s go routines are recycled", pid, app, config.ComponentGoroutinePool)
100
101
                if !allExited() {
102
                        log.Printf("%v [Gofusion] %s %s exit without all goroutines recycled [exists%v]",
103
                                pid, app, config.ComponentGoroutinePool, showRoutine(opt.AppName))
104
                }
105
106
                delete(ignored, opt.AppName)
107
                delete(idle, opt.AppName)
108
                delete(routines, opt.AppName)
109
        }
110
}
func startDaemonRoutines
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/metrics.go:

39
func startDaemonRoutines(ctx context.Context, appName string, conf *Conf) {
40
        ticker := time.Tick(time.Second * 5)
41
        app := config.Use(appName).AppName()
42
        labels := []metrics.Label{}
43
        lastNumGc := atomic.NewUint32(0)
44
45
        log.Printf("%v [Gofusion] %s %s metrics start", syscall.Getpid(), app, config.ComponentGoroutinePool)
46
        for {
47
                select {
48
                case <-ctx.Done():
49
                        log.Printf("%v [Gofusion] %s %s metrics exited",
50
                                syscall.Getpid(), app, config.ComponentGoroutinePool)
51
                        return
52
                case <-ticker:
53
                        go metricsRuntime(ctx, appName, lastNumGc, conf, labels)
54
                }
55
        }
56
}
func Promise
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

188
func Promise(fn any, async bool, opts ...utils.OptionExtender) *Future {
189
        opt := utils.ApplyOptions[candyOption](opts...)
190
        funcName := utils.GetFuncName(fn)
191
        allocate(opt.appName, 1, &NewPoolOption{ApplyTimeout: -1}, ignoreRecycled())
192
        defer func() {
193
                release(opt.appName, nil, ignoreRecycled())
194
                delRoutine(opt.appName, funcName)
195
                if opt.wg != nil {
196
                        opt.wg.Done()
197
                }
198
        }()
199
200
        addRoutine(opt.appName, funcName)
201
        return wrapPromise(fn, async && !forceSync(opt.appName), opts...).
202
                OnFailure(func(v any) {
203
                        if opt.ch == nil {
204
                                log.Printf("[Gofusion] %s catches an error in routine.Loop function: \n"+
205
                                        "error: %s\nfunc: %s\nfunc signature: %T",
206
                                        config.ComponentGoroutinePool, v, utils.GetFuncName(fn), fn)
207
                        }
208
                }).
209
                OnComplete(func(v any) {
210
                        if opt.ch != nil {
211
                                opt.ch <- v
212
                        }
213
                })
214
}
func addRoutine
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/types.go:

55
func addRoutine(appName, name string) {
56
        locker.Lock()
57
        defer locker.Unlock()
58
59
        if _, ok := routines[appName]; !ok {
60
                routines[appName] = make(map[string]int)
61
        }
62
        routines[appName][name]++
63
}
func @91:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

91
func() {
92
                        release(opt.appName, nil, nil)
93
                        delRoutine(opt.appName, funcName)
94
                        if opt.wg != nil {
95
                                opt.wg.Done()
96
                        }
97
                        wg.Done()
98
                }
func @53:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

53
func() {
54
                        release(opt.appName, nil, nil)
55
                        delRoutine(opt.appName, funcName)
56
                        if opt.wg != nil {
57
                                opt.wg.Done()
58
                        }
59
                        wg.Done()
60
                }
func Loop
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

128
func Loop(task any, opts ...utils.OptionExtender) {
129
        opt := utils.ApplyOptions[candyOption](opts...)
130
        allocate(opt.appName, 1, &NewPoolOption{ApplyTimeout: -1}, ignoreRecycled())
131
        exec := func() {
132
                defer func() {
133
                        release(opt.appName, nil, ignoreRecycled())
134
                        if opt.wg != nil {
135
                                opt.wg.Done()
136
                        }
137
                }()
138
                wrapPromise(task, false, opts...).
139
                        OnFailure(func(v any) {
140
                                if opt.ch == nil {
141
                                        log.Printf("[Gofusion] %s catches an error in routine.Loop function: \n"+
142
                                                "error: %s\nfunc: %s\nfunc signature: %T",
143
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
144
                                }
145
                        }).
146
                        OnComplete(func(v any) {
147
                                if opt.ch != nil {
148
                                        opt.ch <- v
149
                                }
150
                        })
151
        }
152
153
        go exec()
154
}
func @192:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

192
func() {
193
                release(opt.appName, nil, ignoreRecycled())
194
                delRoutine(opt.appName, funcName)
195
                if opt.wg != nil {
196
                        opt.wg.Done()
197
                }
198
        }
func Future.GetChan
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

114
func (f *Future) GetChan() <-chan *Result {
115
        c := make(chan *Result, 1)
116
        f.OnComplete(func(v any) {
117
                c <- f.loadResult()
118
        }).OnCancel(func() {
119
                c <- f.loadResult()
120
        })
121
        return c
122
}
func @52:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

52
func() {
53
                defer func() {
54
                        release(opt.appName, nil, nil)
55
                        delRoutine(opt.appName, funcName)
56
                        if opt.wg != nil {
57
                                opt.wg.Done()
58
                        }
59
                        wg.Done()
60
                }()
61
62
                addRoutine(opt.appName, funcName)
63
                wrapPromise(task, false, opts...).
64
                        OnFailure(func(v any) {
65
                                if opt.ch == nil {
66
                                        log.Printf("[Gofusion] %s catches an error in routine.Go function: \n"+
67
                                                "error: %s\nfunc: %s\nfunc signature: %T",
68
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
69
                                }
70
                        }).
71
                        OnComplete(func(v any) {
72
                                if opt.ch != nil {
73
                                        opt.ch <- v
74
                                }
75
                        })
76
        }
func addPool
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

167
func addPool(appName, name string, pool Pool) {
168
        rwlock.Lock()
169
        defer rwlock.Unlock()
170
        pools[appName][name] = pool
171
}
func NewPromise
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

100
func NewPromise() *promise {
101
        val := &futureVal{
102
                dones:   make([]func(v any), 0, 8),
103
                fails:   make([]func(v any), 0, 8),
104
                always:  make([]func(v any), 0, 4),
105
                cancels: make([]func(), 0, 2),
106
                pipes:   make([]*pipe, 0, 4),
107
        }
108
        f := &promise{
109
                Future: &Future{
110
                        Id:    rand.Int(),
111
                        final: make(chan struct{}),
112
                        val:   unsafe.Pointer(val),
113
                },
114
        }
115
        return f
116
}
func @132:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

132
func() {
133
                        release(opt.appName, nil, ignoreRecycled())
134
                        if opt.wg != nil {
135
                                opt.wg.Done()
136
                        }
137
                }
func @90:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

90
func() {
91
                defer func() {
92
                        release(opt.appName, nil, nil)
93
                        delRoutine(opt.appName, funcName)
94
                        if opt.wg != nil {
95
                                opt.wg.Done()
96
                        }
97
                        wg.Done()
98
                }()
99
100
                addRoutine(opt.appName, funcName)
101
                select {
102
                case <-ctx.Done():
103
                case <-wrapPromise(task, false, opts...).
104
                        OnFailure(func(v any) {
105
                                if opt.ch == nil {
106
                                        log.Printf("[Gofusion] %s catches an error in routine.Goc function: \n"+
107
                                                "error: %s\nfunc: %s\nfunc signature: %T",
108
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
109
                                }
110
                        }).
111
                        OnComplete(func(v any) {
112
                                if opt.ch != nil {
113
                                        opt.ch <- v
114
                                }
115
                        }).
116
                        GetChan():
117
                }
118
        }
func configs
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

112
func configs(appName string) (conf Conf) {
113
        _ = config.Use(appName).LoadComponentConfig(config.ComponentGoroutinePool, &conf)
114
        return
115
}
func @240:3
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

240
func() {
241
                        defer func() {
242
                                if e := recover(); e != nil {
243
                                        err := newErrorWithStacks(e)
244
                                        fmt.Println("error happens:\n ", err)
245
                                }
246
                        }()
247
                        f(e)
248
                }
func @104:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

104
func(v any) {
105
                                if opt.ch == nil {
106
                                        log.Printf("[Gofusion] %s catches an error in routine.Goc function: \n"+
107
                                                "error: %s\nfunc: %s\nfunc signature: %T",
108
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
109
                                }
110
                        }
func Future.OnCancel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

187
func (f *Future) OnCancel(callback func()) *Future {
188
        f.addCallback(callback, CallbackCancel)
189
        return f
190
}
func Future.OnComplete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

180
func (f *Future) OnComplete(callback func(v any)) *Future {
181
        f.addCallback(callback, CallbackAlways)
182
        return f
183
}
func @131:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

131
func() {
132
                defer func() {
133
                        release(opt.appName, nil, ignoreRecycled())
134
                        if opt.wg != nil {
135
                                opt.wg.Done()
136
                        }
137
                }()
138
                wrapPromise(task, false, opts...).
139
                        OnFailure(func(v any) {
140
                                if opt.ch == nil {
141
                                        log.Printf("[Gofusion] %s catches an error in routine.Loop function: \n"+
142
                                                "error: %s\nfunc: %s\nfunc signature: %T",
143
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
144
                                }
145
                        }).
146
                        OnComplete(func(v any) {
147
                                if opt.ch != nil {
148
                                        opt.ch <- v
149
                                }
150
                        })
151
        }
func Future.OnFailure
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

170
func (f *Future) OnFailure(callback func(v any)) *Future {
171
        f.addCallback(callback, CallbackFail)
172
        return f
173
}
func Future.loadResult
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

280
func (f *Future) loadResult() *Result {
281
        val := f.loadVal()
282
        return val.r
283
}
func Future.loadVal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

286
func (f *Future) loadVal() *futureVal {
287
        r := atomic.LoadPointer(&f.val)
288
        return (*futureVal)(r)
289
}
func Future.Get
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

128
func (f *Future) Get() (val any, err error) {
129
        <-f.final
130
        return getFutureReturnVal(f.loadResult())
131
}
func @99:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

99
func(...any) (any, error) { e := v(); return nil, e }
func @71:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

71
func(v any) {
72
                                if opt.ch != nil {
73
                                        opt.ch <- v
74
                                }
75
                        }
func pool.Release
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

48
func (p *pool) Release(opts ...utils.OptionExtender) {
49
        defer release(p.appName, p, opts...)
50
        p.pool.Release()
51
}
func forSlice
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

238
func forSlice(s []func(v any), f func(func(v any))) {
239
        for _, e := range s {
240
                func() {
241
                        defer func() {
242
                                if e := recover(); e != nil {
243
                                        err := newErrorWithStacks(e)
244
                                        fmt.Println("error happens:\n ", err)
245
                                }
246
                        }()
247
                        f(e)
248
                }()
249
        }
250
}
func @97:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

97
func(...any) (any, error) { v(); return nil, nil }
func @38:24
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

38
func() { e = wrapFn(opt.args...) }
func @96:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

96
func(o *internalOption) {
97
                o.ignoreRecycled = true
98
        }
func @319:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

319
func() {
320
                                        execCallback(r, v.dones, v.fails, v.always, v.cancels)
321
                                }
func WithoutTimeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

226
func WithoutTimeout() utils.OptionFunc[NewPoolOption] {
227
        return func(o *NewPoolOption) {
228
                o.ApplyTimeout = -1
229
        }
230
}
func @227:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

227
func(o *NewPoolOption) {
228
                o.ApplyTimeout = -1
229
        }
func promise.Resolve
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

56
func (p *promise) Resolve(v any) (e error) {
57
        return p.setResult(&Result{v, ResultSuccess})
58
}
func promise.Reject
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

62
func (p *promise) Reject(err error) (e error) {
63
        return p.setResult(&Result{err, ResultFailure})
64
}
func AppName
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

42
func AppName(name string) utils.OptionFunc[candyOption] {
43
        return func(o *candyOption) {
44
                o.appName = name
45
        }
46
}
func @116:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

116
func(v any) {
117
                c <- f.loadResult()
118
        }
func @43:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

43
func(o *candyOption) {
44
                o.appName = name
45
        }
func init
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

121
func init() {
122
        config.AddComponent(config.ComponentGoroutinePool, Construct)
123
}
func forceSync
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

117
func forceSync(appName string) bool {
118
        return configs(appName).ForceSync
119
}
func @37:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

37
func(o *candyOption) {
38
                o.ch = ch
39
        }
func @80:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

80
func() bool {
81
                        return idle[opt.AppName].Load() == int64(conf.MaxRoutineAmount)-ignored[opt.AppName].Load()
82
                }
func Channel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

36
func Channel(ch chan<- any) utils.OptionFunc[candyOption] {
37
        return func(o *candyOption) {
38
                o.ch = ch
39
        }
40
}
func @31:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

31
func(o *candyOption) {
32
                o.wg = wg
33
        }
func WaitGroup
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

30
func WaitGroup(wg *sync.WaitGroup) utils.OptionFunc[candyOption] {
31
        return func(o *candyOption) {
32
                o.wg = wg
33
        }
34
}
func @230:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

230
func(f func(v any)) { f(r.Result) }
func @229:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

229
func(s []func(v any)) {
230
                forSlice(s, func(f func(v any)) { f(r.Result) })
231
        }
func @25:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

25
func(o *candyOption) {
26
                o.args = append(o.args, args...)
27
        }
func ignoreRecycled
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

95
func ignoreRecycled() utils.OptionFunc[internalOption] {
96
        return func(o *internalOption) {
97
                o.ignoreRecycled = true
98
        }
99
}
func Args
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

24
func Args(args ...any) utils.OptionFunc[candyOption] {
25
        return func(o *candyOption) {
26
                o.args = append(o.args, args...)
27
        }
28
}
func NewPool
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

57
func NewPool(name string, size int, opts ...utils.OptionExtender) (p Pool) {
58
        o := utils.ApplyOptions[NewPoolOption](opts...)
59
        opt := utils.ApplyOptions[candyOption](opts...)
60
        if o.Logger == nil {
61
                o.Logger = defaultLogger[opt.appName]
62
        }
63
64
        validate(opt.appName, name)
65
        allocate(opt.appName, size, o)
66
67
        antsPool, err := ants.NewPool(size, ants.WithOptions(ants.Options{
68
                ExpiryDuration:   o.ExpiryDuration,
69
                PreAlloc:         o.PreAlloc,
70
                MaxBlockingTasks: o.MaxBlockingTasks,
71
                Nonblocking:      o.Nonblocking,
72
                PanicHandler:     o.PanicHandler,
73
                Logger:           o.Logger,
74
                DisablePurge:     o.DisablePurge,
75
        }))
76
        if err != nil {
77
                panic(err)
78
        }
79
80
        p = &pool{appName: opt.appName, name: name, pool: antsPool, option: o}
81
        addPool(opt.appName, name, p)
82
        return
83
}
func allocate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

107
func allocate(appName string, size int, o *NewPoolOption, opts ...utils.OptionExtender) {
108
        oo := utils.ApplyOptions[internalOption](opts...)
109
        demands := int64(size)
110
        rwlock.RLock()
111
        defer rwlock.RUnlock()
112
        if idle[appName].Load()-demands < 0 && o.ApplyTimeout == 0 {
113
                panic(ErrPoolOverload)
114
        }
115
116
        if o.ApplyTimeout < 0 {
117
                o.ApplyTimeout = math.MaxInt64
118
        }
119
120
        t := time.NewTimer(o.ApplyTimeout)
121
        for {
122
                select {
123
                case <-t.C:
124
                        panic(ErrTimeout)
125
                default:
126
                        minuend := idle[appName].Load()
127
                        diff := minuend - demands
128
                        // main thread is a goroutine as well, so diff should be greater than 0
129
                        if diff <= 0 || !idle[appName].CompareAndSwap(minuend, diff) {
130
                                continue
131
                        }
132
                        if oo.ignoreRecycled {
133
                                ignored[appName].Add(demands)
134
                        }
135
136
                        return
137
                }
138
        }
139
}
func Future.setResult
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

292
func (f *Future) setResult(r *Result) (e error) {
293
        defer func() {
294
                if err := getError(recover()); err != nil {
295
                        e = err
296
                        fmt.Printf("\nerror in setResult(): %s\n%s\n", err, debug.Stack())
297
                }
298
        }()
299
300
        e = errors.New("cannot resolve/reject/cancel more than once")
301
302
        for {
303
                v := f.loadVal()
304
                if v.r != nil {
305
                        return
306
                }
307
                newVal := *v
308
                newVal.r = r
309
310
                // Use CAS operation to ensure that the state of promise isn't changed.
311
                // If the state is changed, must get the latest state and try to call CAS again.
312
                // No ABA issue in this case because address of all objects are different.
313
                if atomic.CompareAndSwapPointer(&f.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
314
                        //Close chEnd then all Get() and GetOrTimeout() will be unblocked
315
                        close(f.final)
316
317
                        //call callback functions and start the promise pipeline
318
                        if len(v.dones) > 0 || len(v.fails) > 0 || len(v.always) > 0 || len(v.cancels) > 0 {
319
                                Go(func() {
320
                                        execCallback(r, v.dones, v.fails, v.always, v.cancels)
321
                                }, AppName(f.AppName))
322
                        }
323
324
                        //start the pipeline
325
                        if len(v.pipes) > 0 {
326
                                Go(func() {
327
                                        for _, pipe := range v.pipes {
328
                                                pipeTask, pipePromise := pipe.getPipe(r.Typ == ResultSuccess)
329
                                                startPipe(r, pipeTask, pipePromise)
330
                                        }
331
                                }, AppName(f.AppName))
332
                        }
333
                        e = nil
334
                        break
335
                }
336
        }
337
        return
338
}
func release
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

141
func release(appName string, p *pool, opts ...utils.OptionExtender) {
142
        o := utils.ApplyOptions[internalOption](opts...)
143
        capacity := int64(1)
144
        if pools == nil || pools[appName] == nil || idle == nil || idle[appName] == nil {
145
                return
146
        }
147
148
        if p != nil {
149
                if !o.ignoreMutex {
150
                        rwlock.Lock()
151
                        defer rwlock.Unlock()
152
                }
153
                delete(pools[appName], p.name)
154
                capacity = int64(p.pool.Cap())
155
        }
156
157
        alloc := idle[appName]
158
        if alloc == nil {
159
                return
160
        }
161
        alloc.Add(capacity)
162
        if o != nil && o.ignoreRecycled {
163
                alloc.Sub(capacity)
164
        }
165
}
func Goc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

86
func Goc(ctx context.Context, task any, opts ...utils.OptionExtender) {
87
        funcName := utils.GetFuncName(task)
88
        opt := utils.ApplyOptions[candyOption](opts...)
89
        allocate(opt.appName, 1, &NewPoolOption{ApplyTimeout: -1})
90
        exec := func() {
91
                defer func() {
92
                        release(opt.appName, nil, nil)
93
                        delRoutine(opt.appName, funcName)
94
                        if opt.wg != nil {
95
                                opt.wg.Done()
96
                        }
97
                        wg.Done()
98
                }()
99
100
                addRoutine(opt.appName, funcName)
101
                select {
102
                case <-ctx.Done():
103
                case <-wrapPromise(task, false, opts...).
104
                        OnFailure(func(v any) {
105
                                if opt.ch == nil {
106
                                        log.Printf("[Gofusion] %s catches an error in routine.Goc function: \n"+
107
                                                "error: %s\nfunc: %s\nfunc signature: %T",
108
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
109
                                }
110
                        }).
111
                        OnComplete(func(v any) {
112
                                if opt.ch != nil {
113
                                        opt.ch <- v
114
                                }
115
                        }).
116
                        GetChan():
117
                }
118
        }
119
120
        wg.Add(1)
121
        if forceSync(opt.appName) {
122
                exec()
123
        } else {
124
                go exec()
125
        }
126
}
func Go
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

48
func Go(task any, opts ...utils.OptionExtender) {
49
        funcName := utils.GetFuncName(task)
50
        opt := utils.ApplyOptions[candyOption](opts...)
51
        allocate(opt.appName, 1, &NewPoolOption{ApplyTimeout: -1})
52
        exec := func() {
53
                defer func() {
54
                        release(opt.appName, nil, nil)
55
                        delRoutine(opt.appName, funcName)
56
                        if opt.wg != nil {
57
                                opt.wg.Done()
58
                        }
59
                        wg.Done()
60
                }()
61
62
                addRoutine(opt.appName, funcName)
63
                wrapPromise(task, false, opts...).
64
                        OnFailure(func(v any) {
65
                                if opt.ch == nil {
66
                                        log.Printf("[Gofusion] %s catches an error in routine.Go function: \n"+
67
                                                "error: %s\nfunc: %s\nfunc signature: %T",
68
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
69
                                }
70
                        }).
71
                        OnComplete(func(v any) {
72
                                if opt.ch != nil {
73
                                        opt.ch <- v
74
                                }
75
                        })
76
        }
77
78
        wg.Add(1)
79
        if forceSync(opt.appName) {
80
                exec()
81
        } else {
82
                go exec()
83
        }
84
}
func start
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

508
func start(act any, async bool, opts ...utils.OptionExtender) *Future {
509
        p := NewPromise()
510
        if f, ok := act.(*Future); ok {
511
                return f
512
        }
513
514
        opt := utils.ApplyOptions[candyOption](opts...)
515
        p.AppName = opt.appName
516
        if action := getAct(p, act); action != nil {
517
                if !async {
518
                        // sync call
519
                        r, err := action(opt)
520
                        if p.IsCancelled() {
521
                                _ = p.Cancel()
522
                        } else {
523
                                if err == nil {
524
                                        _ = p.Resolve(r)
525
                                } else {
526
                                        _ = p.Reject(err)
527
                                }
528
                        }
529
                } else {
530
                        // async call
531
                        Go(func() {
532
                                r, err := action(opt)
533
                                if p.IsCancelled() {
534
                                        _ = p.Cancel()
535
                                } else {
536
                                        if err == nil {
537
                                                _ = p.Resolve(r)
538
                                        } else {
539
                                                _ = p.Reject(err)
540
                                        }
541
                                }
542
                        }, AppName(opt.appName))
543
                }
544
        }
545
546
        return p.Future
547
}
func delRoutine
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/types.go:

65
func delRoutine(appName, name string) {
66
        locker.Lock()
67
        defer locker.Unlock()
68
        if routines == nil || routines[appName] == nil {
69
                return
70
        }
71
72
        if routines[appName][name]--; routines[appName][name] <= 0 {
73
                delete(routines, name)
74
        }
75
}
func @132:6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

132
func(opt *candyOption) (r any, err error) {
133
                defer func() {
134
                        if e := recover(); e != nil {
135
                                err = newErrorWithStacks(e)
136
                        }
137
                }()
138
139
                if canCancel {
140
                        r, err = act2(canceller, opt.args...)
141
                } else {
142
                        r, err = act1(opt.args...)
143
                }
144
145
                return
146
        }
func pool.Submit
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

34
func (p *pool) Submit(task any, opts ...utils.OptionExtender) (e error) {
35
        opt := utils.ApplyOptions[candyOption](opts...)
36
        wrapFn := utils.WrapFunc1[error](task)
37
        if !forceSync(p.appName) {
38
                return p.pool.Submit(func() { e = wrapFn(opt.args...) })
39
        }
40
41
        return wrapFn(opt.args...)
42
}
func @74:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/construct.go:

74
func() {
75
                rwlock.Lock()
76
                defer rwlock.Unlock()
77
78
                pid := syscall.Getpid()
79
                app := config.Use(opt.AppName).AppName()
80
                allExited := func() bool {
81
                        return idle[opt.AppName].Load() == int64(conf.MaxRoutineAmount)-ignored[opt.AppName].Load()
82
                }
83
84
                // waiting for pool
85
                if pools != nil {
86
                        for name, pool := range pools[opt.AppName] {
87
                                if err := pool.ReleaseTimeout(maxReleaseTime, ignoreMutex()); err != nil {
88
                                        log.Printf("%v [Gofusion] %s %s exit with releasing pool %s failed because %s",
89
                                                pid, app, config.ComponentGoroutinePool, name, err)
90
                                }
91
                                delete(pools[opt.AppName], name)
92
                        }
93
                }
94
95
                log.Printf("%v [Gofusion] %s %s pool routines are recycled", pid, app, config.ComponentGoroutinePool)
96
97
                // waiting for go
98
                utils.Timeout(maxReleaseTime, utils.TimeoutWg(&wg))
99
                log.Printf("%v [Gofusion] %s %s go routines are recycled", pid, app, config.ComponentGoroutinePool)
100
101
                if !allExited() {
102
                        log.Printf("%v [Gofusion] %s %s exit without all goroutines recycled [exists%v]",
103
                                pid, app, config.ComponentGoroutinePool, showRoutine(opt.AppName))
104
                }
105
106
                delete(ignored, opt.AppName)
107
                delete(idle, opt.AppName)
108
                delete(routines, opt.AppName)
109
        }
func wrapPromise
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

225
func wrapPromise(fn any, async bool, opts ...utils.OptionExtender) *Future {
226
        // check supported function
227
        switch fn.(type) {
228
        case func(),
229
                func() error,
230
                func() (any, error),
231
                func(Canceller),
232
                func(Canceller) error,
233
                func(Canceller) (any, error):
234
235
                return start(fn, async, opts...)
236
237
        default:
238
                typ := reflect.TypeOf(fn)
239
                if typ.Kind() != reflect.Func {
240
                        return WrapFuture(errors.Errorf("unsupported function type %T", fn), opts...)
241
                }
242
                if typ.NumOut() > 0 && (typ.NumOut() > 2 ||
243
                        typ.Out(typ.NumOut()-1) != constant.ErrorType ||
244
                        (typ.NumOut() == 2 && typ.Out(0) != constant.AnyType)) {
245
                        return WrapFuture(errors.Errorf("unsupported function signature %T", fn), opts...)
246
                }
247
248
                return start(fn, async, opts...)
249
        }
250
}
func validate
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

173
func validate(appName, name string) {
174
        rwlock.RLock()
175
        defer rwlock.RUnlock()
176
        if _, ok := pools[appName][name]; ok {
177
                panic(ErrDuplicatedName)
178
        }
179
}
func Future.IsCancelled
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

87
func (f *Future) IsCancelled() bool {
88
        val := f.loadVal()
89
90
        if val != nil && val.r != nil && val.r.Typ == ResultCancelled {
91
                return true
92
        } else {
93
                return false
94
        }
95
}
func Future.addCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

341
func (f *Future) addCallback(callback any, t callbackType) {
342
        if callback == nil {
343
                return
344
        }
345
        if (t == CallbackDone) ||
346
                (t == CallbackFail) ||
347
                (t == CallbackAlways) {
348
                if _, ok := callback.(func(v any)); !ok {
349
                        panic(errors.New("callback function spec must be func(v any)"))
350
                }
351
        } else if t == CallbackCancel {
352
                if _, ok := callback.(func()); !ok {
353
                        panic(errors.New("callback function spec must be func()"))
354
                }
355
        }
356
357
        for {
358
                v := f.loadVal()
359
                r := v.r
360
                if r == nil {
361
                        newVal := *v
362
                        switch t {
363
                        case CallbackDone:
364
                                newVal.dones = append(newVal.dones, callback.(func(v any)))
365
                        case CallbackFail:
366
                                newVal.fails = append(newVal.fails, callback.(func(v any)))
367
                        case CallbackAlways:
368
                                newVal.always = append(newVal.always, callback.(func(v any)))
369
                        case CallbackCancel:
370
                                newVal.cancels = append(newVal.cancels, callback.(func()))
371
                        }
372
373
                        //use CAS to ensure that the state of Future is not changed,
374
                        //if the state is changed, will retry CAS operation.
375
                        if atomic.CompareAndSwapPointer(&f.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
376
                                break
377
                        }
378
                } else {
379
                        if (t == CallbackDone && r.Typ == ResultSuccess) ||
380
                                (t == CallbackFail && r.Typ == ResultFailure) ||
381
                                (t == CallbackAlways && r.Typ != ResultCancelled) {
382
                                callbackFunc := callback.(func(v any))
383
                                callbackFunc(r.Result)
384
                        } else if t == CallbackCancel && r.Typ == ResultCancelled {
385
                                callbackFunc := callback.(func())
386
                                callbackFunc()
387
                        }
388
                        break
389
                }
390
        }
391
}
func @66:21
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/metrics.go:

66
func() {
67
                var routineNum int64
68
                if idle != nil && idle[appName] != nil {
69
                        routineNum = int64(conf.MaxRoutineAmount) - idle[appName].Load()
70
                }
71
72
                // export number of Goroutines
73
                totalRoutineNum := runtime.NumGoroutine()
74
75
                // export memory stats
76
                var stats runtime.MemStats
77
                runtime.ReadMemStats(&stats)
78
79
                // export info about the last few GC runs
80
                // handle wrap around
81
                if stats.NumGC < lastNumGc.Load() {
82
                        lastNumGc.Store(0)
83
                }
84
85
                // ensure we don't scan more than 256
86
                if stats.NumGC-lastNumGc.Load() >= 256 {
87
                        lastNumGc.Store(stats.NumGC - 255)
88
                }
89
90
                app := config.Use(appName).AppName()
91
                totalGoRoutinesKey := append([]string{app}, metricsRuntimeTotalGoroutinesKey...)
92
                goroutineKey := append([]string{app}, metricsRuntimeGoroutinesKey...)
93
                allocBytesKey := append([]string{app}, metricsRuntimeAllocBytesKey...)
94
                sysBytesKey := append([]string{app}, metricsRuntimeSysBytesKey...)
95
                mallocCountKey := append([]string{app}, metricsRuntimeMallocCountKey...)
96
                freeCountKey := append([]string{app}, metricsRuntimeFreeCountKey...)
97
                heapObjectsKey := append([]string{app}, metricsRuntimeHeapObjectsKey...)
98
                gcRunsKey := append([]string{app}, metricsRuntimeGCRunsKey...)
99
                totalSTWLatencyKey := append([]string{app}, metricsRuntimeTotalSTWLatencyKey...)
100
101
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
102
                        select {
103
                        case <-ctx.Done():
104
                                return
105
                        default:
106
                                if m.IsEnableServiceLabel() {
107
                                        m.SetGauge(ctx, totalGoRoutinesKey, float64(totalRoutineNum), metrics.Labels(labels))
108
                                        m.SetGauge(ctx, goroutineKey, float64(routineNum), metrics.Labels(labels))
109
                                        m.SetGauge(ctx, allocBytesKey, float64(stats.Alloc), metrics.Labels(labels))
110
                                        m.SetGauge(ctx, sysBytesKey, float64(stats.Sys), metrics.Labels(labels))
111
                                        m.SetGauge(ctx, mallocCountKey, float64(stats.Mallocs), metrics.Labels(labels))
112
                                        m.SetGauge(ctx, freeCountKey, float64(stats.Frees), metrics.Labels(labels))
113
                                        m.SetGauge(ctx, heapObjectsKey, float64(stats.HeapObjects), metrics.Labels(labels))
114
                                        m.SetGauge(ctx, gcRunsKey, float64(stats.NumGC), metrics.Labels(labels))
115
                                        for i := lastNumGc.Load(); i < stats.NumGC; i++ {
116
                                                m.AddSample(ctx, totalSTWLatencyKey, float64(stats.PauseNs[i%256]), metrics.Labels(labels))
117
                                        }
118
                                } else {
119
                                        m.SetGauge(ctx, metricsRuntimeTotalGoroutinesKey, float64(totalRoutineNum), metrics.Labels(labels))
120
                                        m.SetGauge(ctx, metricsRuntimeGoroutinesKey, float64(routineNum), metrics.Labels(labels))
121
                                        m.SetGauge(ctx, metricsRuntimeAllocBytesKey, float64(stats.Alloc), metrics.Labels(labels))
122
                                        m.SetGauge(ctx, metricsRuntimeSysBytesKey, float64(stats.Sys), metrics.Labels(labels))
123
                                        m.SetGauge(ctx, metricsRuntimeMallocCountKey, float64(stats.Mallocs), metrics.Labels(labels))
124
                                        m.SetGauge(ctx, metricsRuntimeFreeCountKey, float64(stats.Frees), metrics.Labels(labels))
125
                                        m.SetGauge(ctx, metricsRuntimeHeapObjectsKey, float64(stats.HeapObjects), metrics.Labels(labels))
126
                                        m.SetGauge(ctx, metricsRuntimeGCRunsKey, float64(stats.NumGC), metrics.Labels(labels))
127
                                        for i := lastNumGc.Load(); i < stats.NumGC; i++ {
128
                                                m.AddSample(ctx, metricsRuntimeTotalSTWLatencyKey, float64(stats.PauseNs[i%256]),
129
                                                        metrics.Labels(labels),
130
                                                        metrics.PrometheusBuckets(metricsRuntimeTotalSTWLatencyBuckets),
131
                                                )
132
                                        }
133
                                }
134
                        }
135
                }
136
137
                lastNumGc.Store(stats.NumGC)
138
        }
func @531:7
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

531
func() {
532
                                r, err := action(opt)
533
                                if p.IsCancelled() {
534
                                        _ = p.Cancel()
535
                                } else {
536
                                        if err == nil {
537
                                                _ = p.Resolve(r)
538
                                        } else {
539
                                                _ = p.Reject(err)
540
                                        }
541
                                }
542
                        }
func metricsRuntime
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/metrics.go:

58
func metricsRuntime(ctx context.Context, appName string, lastNumGc *atomic.Uint32, conf *Conf, labels []metrics.Label) {
59
        select {
60
        case <-ctx.Done():
61
                return
62
        default:
63
64
        }
65
66
        _, _ = utils.Catch(func() {
67
                var routineNum int64
68
                if idle != nil && idle[appName] != nil {
69
                        routineNum = int64(conf.MaxRoutineAmount) - idle[appName].Load()
70
                }
71
72
                // export number of Goroutines
73
                totalRoutineNum := runtime.NumGoroutine()
74
75
                // export memory stats
76
                var stats runtime.MemStats
77
                runtime.ReadMemStats(&stats)
78
79
                // export info about the last few GC runs
80
                // handle wrap around
81
                if stats.NumGC < lastNumGc.Load() {
82
                        lastNumGc.Store(0)
83
                }
84
85
                // ensure we don't scan more than 256
86
                if stats.NumGC-lastNumGc.Load() >= 256 {
87
                        lastNumGc.Store(stats.NumGC - 255)
88
                }
89
90
                app := config.Use(appName).AppName()
91
                totalGoRoutinesKey := append([]string{app}, metricsRuntimeTotalGoroutinesKey...)
92
                goroutineKey := append([]string{app}, metricsRuntimeGoroutinesKey...)
93
                allocBytesKey := append([]string{app}, metricsRuntimeAllocBytesKey...)
94
                sysBytesKey := append([]string{app}, metricsRuntimeSysBytesKey...)
95
                mallocCountKey := append([]string{app}, metricsRuntimeMallocCountKey...)
96
                freeCountKey := append([]string{app}, metricsRuntimeFreeCountKey...)
97
                heapObjectsKey := append([]string{app}, metricsRuntimeHeapObjectsKey...)
98
                gcRunsKey := append([]string{app}, metricsRuntimeGCRunsKey...)
99
                totalSTWLatencyKey := append([]string{app}, metricsRuntimeTotalSTWLatencyKey...)
100
101
                for _, m := range metrics.Internal(metrics.AppName(appName)) {
102
                        select {
103
                        case <-ctx.Done():
104
                                return
105
                        default:
106
                                if m.IsEnableServiceLabel() {
107
                                        m.SetGauge(ctx, totalGoRoutinesKey, float64(totalRoutineNum), metrics.Labels(labels))
108
                                        m.SetGauge(ctx, goroutineKey, float64(routineNum), metrics.Labels(labels))
109
                                        m.SetGauge(ctx, allocBytesKey, float64(stats.Alloc), metrics.Labels(labels))
110
                                        m.SetGauge(ctx, sysBytesKey, float64(stats.Sys), metrics.Labels(labels))
111
                                        m.SetGauge(ctx, mallocCountKey, float64(stats.Mallocs), metrics.Labels(labels))
112
                                        m.SetGauge(ctx, freeCountKey, float64(stats.Frees), metrics.Labels(labels))
113
                                        m.SetGauge(ctx, heapObjectsKey, float64(stats.HeapObjects), metrics.Labels(labels))
114
                                        m.SetGauge(ctx, gcRunsKey, float64(stats.NumGC), metrics.Labels(labels))
115
                                        for i := lastNumGc.Load(); i < stats.NumGC; i++ {
116
                                                m.AddSample(ctx, totalSTWLatencyKey, float64(stats.PauseNs[i%256]), metrics.Labels(labels))
117
                                        }
118
                                } else {
119
                                        m.SetGauge(ctx, metricsRuntimeTotalGoroutinesKey, float64(totalRoutineNum), metrics.Labels(labels))
120
                                        m.SetGauge(ctx, metricsRuntimeGoroutinesKey, float64(routineNum), metrics.Labels(labels))
121
                                        m.SetGauge(ctx, metricsRuntimeAllocBytesKey, float64(stats.Alloc), metrics.Labels(labels))
122
                                        m.SetGauge(ctx, metricsRuntimeSysBytesKey, float64(stats.Sys), metrics.Labels(labels))
123
                                        m.SetGauge(ctx, metricsRuntimeMallocCountKey, float64(stats.Mallocs), metrics.Labels(labels))
124
                                        m.SetGauge(ctx, metricsRuntimeFreeCountKey, float64(stats.Frees), metrics.Labels(labels))
125
                                        m.SetGauge(ctx, metricsRuntimeHeapObjectsKey, float64(stats.HeapObjects), metrics.Labels(labels))
126
                                        m.SetGauge(ctx, metricsRuntimeGCRunsKey, float64(stats.NumGC), metrics.Labels(labels))
127
                                        for i := lastNumGc.Load(); i < stats.NumGC; i++ {
128
                                                m.AddSample(ctx, metricsRuntimeTotalSTWLatencyKey, float64(stats.PauseNs[i%256]),
129
                                                        metrics.Labels(labels),
130
                                                        metrics.PrometheusBuckets(metricsRuntimeTotalSTWLatencyBuckets),
131
                                                )
132
                                        }
133
                                }
134
                        }
135
                }
136
137
                lastNumGc.Store(stats.NumGC)
138
        })
139
}
func execCallback
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

201
func execCallback(r *Result,
202
        dones []func(v any),
203
        fails []func(v any),
204
        always []func(v any),
205
        cancels []func()) {
206
207
        if r.Typ == ResultCancelled {
208
                for _, f := range cancels {
209
                        func() {
210
                                defer func() {
211
                                        if e := recover(); e != nil {
212
                                                err := newErrorWithStacks(e)
213
                                                fmt.Println("error happens:\n ", err)
214
                                        }
215
                                }()
216
                                f()
217
                        }()
218
                }
219
                return
220
        }
221
222
        var callbacks []func(v any)
223
        if r.Typ == ResultSuccess {
224
                callbacks = dones
225
        } else {
226
                callbacks = fails
227
        }
228
229
        forFs := func(s []func(v any)) {
230
                forSlice(s, func(f func(v any)) { f(r.Result) })
231
        }
232
233
        forFs(callbacks)
234
        forFs(always)
235
236
}
func getAct
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

87
func getAct(p *promise, act any) (f func(opt *candyOption) (r any, err error)) {
88
        var (
89
                act1 func(...any) (any, error)
90
                act2 func(Canceller, ...any) (any, error)
91
        )
92
        canCancel := false
93
94
        // convert the act to the function that has return value and error if act function haven't return value and error
95
        switch v := act.(type) {
96
        case func():
97
                act1 = func(...any) (any, error) { v(); return nil, nil }
98
        case func() error:
99
                act1 = func(...any) (any, error) { e := v(); return nil, e }
100
        case func() (any, error):
101
                act1 = func(a ...any) (any, error) { return v() }
102
        case func(Canceller):
103
                canCancel = true
104
                act2 = func(canceller Canceller, a ...any) (any, error) { v(canceller); return nil, nil }
105
        case func(Canceller) error:
106
                canCancel = true
107
                act2 = func(canceller Canceller, a ...any) (any, error) { e := v(canceller); return nil, e }
108
        case func(Canceller) (any, error):
109
                canCancel = true
110
                act2 = func(canceller Canceller, a ...any) (any, error) { return v(canceller) }
111
        default:
112
                typ := reflect.TypeOf(v)
113
                if typ.Kind() == reflect.Func {
114
                        act1 = utils.WrapFunc2[any, error](v)
115
                } else {
116
                        if e, ok := v.(error); !ok {
117
                                _ = p.Resolve(v)
118
                        } else {
119
                                _ = p.Reject(e)
120
                        }
121
                        return nil
122
                }
123
        }
124
125
        // If parameters of act function has a Canceller interface, the Future will be cancelled.
126
        var canceller Canceller = nil
127
        if p != nil && canCancel {
128
                canceller = p.Canceller()
129
        }
130
131
        // return proxy function of act function
132
        f = func(opt *candyOption) (r any, err error) {
133
                defer func() {
134
                        if e := recover(); e != nil {
135
                                err = newErrorWithStacks(e)
136
                        }
137
                }()
138
139
                if canCancel {
140
                        r, err = act2(canceller, opt.args...)
141
                } else {
142
                        r, err = act1(opt.args...)
143
                }
144
145
                return
146
        }
147
        return
148
}
func @146:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

146
func(v any) {
147
                                if opt.ch != nil {
148
                                        opt.ch <- v
149
                                }
150
                        }
func @133:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

133
func() {
134
                        if e := recover(); e != nil {
135
                                err = newErrorWithStacks(e)
136
                        }
137
                }
func @111:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

111
func(v any) {
112
                                if opt.ch != nil {
113
                                        opt.ch <- v
114
                                }
115
                        }
func @64:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

64
func(v any) {
65
                                if opt.ch == nil {
66
                                        log.Printf("[Gofusion] %s catches an error in routine.Go function: \n"+
67
                                                "error: %s\nfunc: %s\nfunc signature: %T",
68
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
69
                                }
70
                        }
func @209:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

209
func(v any) {
210
                        if opt.ch != nil {
211
                                opt.ch <- v
212
                        }
213
                }
func getFutureReturnVal
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

191
func getFutureReturnVal(r *Result) (any, error) {
192
        if r.Typ == ResultSuccess {
193
                return r.Result, nil
194
        } else if r.Typ == ResultFailure {
195
                return nil, getError(r.Result)
196
        } else {
197
                return nil, getError(r.Result) //&CancelledError{}
198
        }
199
}
func @293:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

293
func() {
294
                if err := getError(recover()); err != nil {
295
                        e = err
296
                        fmt.Printf("\nerror in setResult(): %s\n%s\n", err, debug.Stack())
297
                }
298
        }
func @241:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

241
func() {
242
                                if e := recover(); e != nil {
243
                                        err := newErrorWithStacks(e)
244
                                        fmt.Println("error happens:\n ", err)
245
                                }
246
                        }
func getError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

155
func getError(i any) (e error) {
156
        if i != nil {
157
                switch v := i.(type) {
158
                case error:
159
                        e = v
160
                case string:
161
                        e = errors.New(v)
162
                default:
163
                        if s, ok := i.(stringer); ok {
164
                                e = errors.New(s.String())
165
                        } else {
166
                                e = errors.New(fmt.Sprintf("%v", i))
167
                        }
168
                }
169
        }
170
        return
171
}
func Future.Pipe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

195
func (f *Future) Pipe(callbacks ...any) (result *Future, ok bool) {
196
        if len(callbacks) == 0 ||
197
                (len(callbacks) == 1 && callbacks[0] == nil) ||
198
                (len(callbacks) > 1 && callbacks[0] == nil && callbacks[1] == nil) {
199
                result = f
200
                return
201
        }
202
203
        // ensure all callback functions match the spec "func(v any) *Future"
204
        cs := make([]func(v any) *Future, len(callbacks), len(callbacks))
205
        for i, callback := range callbacks {
206
                switch c := callback.(type) {
207
                case func(v any) *Future:
208
                        cs[i] = c
209
                case func() *Future:
210
                        cs[i] = func(v any) *Future {
211
                                return c()
212
                        }
213
                case func(v any):
214
                        cs[i] = func(v any) *Future {
215
                                return start(func() {
216
                                        c(v)
217
                                }, true)
218
                        }
219
                case func(v any) (r any, err error):
220
                        cs[i] = func(v any) *Future {
221
                                return start(func() (r any, err error) {
222
                                        r, err = c(v)
223
                                        return
224
                                }, true)
225
                        }
226
                case func():
227
                        cs[i] = func(v any) *Future {
228
                                return start(func() {
229
                                        c()
230
                                }, true)
231
                        }
232
                case func() (r any, err error):
233
                        cs[i] = func(v any) *Future {
234
                                return start(func() (r any, err error) {
235
                                        r, err = c()
236
                                        return
237
                                }, true)
238
                        }
239
                default:
240
                        ok = false
241
                        return
242
                }
243
        }
244
245
        for {
246
                v := f.loadVal()
247
                r := v.r
248
                if r != nil {
249
                        result = f
250
                        if r.Typ == ResultSuccess && cs[0] != nil {
251
                                result = cs[0](r.Result)
252
                        } else if r.Typ == ResultFailure && len(cs) > 1 && cs[1] != nil {
253
                                result = cs[1](r.Result)
254
                        }
255
                } else {
256
                        newPipe := &pipe{}
257
                        newPipe.pipeDoneTask = cs[0]
258
                        if len(cs) > 1 {
259
                                newPipe.pipeFailTask = cs[1]
260
                        }
261
                        newPipe.pipePromise = NewPromise()
262
263
                        newVal := *v
264
                        newVal.pipes = append(newVal.pipes, newPipe)
265
266
                        //use CAS to ensure that the state of Future is not changed,
267
                        //if the state is changed, will retry CAS operation.
268
                        if atomic.CompareAndSwapPointer(&f.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
269
                                result = newPipe.pipePromise.Future
270
                                break
271
                        }
272
                }
273
        }
274
275
        ok = true
276
        return
277
}
func WhenAnyMatched
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

284
func WhenAnyMatched(predicate func(any) bool, acts ...any) *Future {
285
        if predicate == nil {
286
                predicate = func(v any) bool { return true }
287
        }
288
289
        opts := make([]utils.OptionExtender, 0, len(acts))
290
        for i, act := range acts {
291
                if opt, ok := act.(utils.OptionExtender); ok {
292
                        opts = append(opts, opt)
293
                        acts = append(acts[:i], acts[i+1:]...)
294
                }
295
        }
296
        opt := utils.ApplyOptions[candyOption](opts...)
297
        fs := make([]*Future, len(acts))
298
        for i, act := range acts {
299
                fs[i] = Promise(act, true, opts...)
300
        }
301
302
        nf, rs := NewPromise(), make([]any, len(fs))
303
        if len(acts) == 0 {
304
                _ = nf.Resolve(nil)
305
        }
306
307
        chFails, chDones := make(chan anyPromiseResult), make(chan anyPromiseResult)
308
309
        Go(func() {
310
                for i, f := range fs {
311
                        k := i
312
                        f.OnSuccess(func(v any) {
313
                                defer func() { _ = recover() }()
314
                                chDones <- anyPromiseResult{result: v, i: k}
315
                        }).OnFailure(func(v any) {
316
                                defer func() { _ = recover() }()
317
                                chFails <- anyPromiseResult{result: v, i: k}
318
                        }).OnCancel(func() {
319
                                defer func() { _ = recover() }()
320
                                chFails <- anyPromiseResult{result: ErrCancelled, i: k}
321
                        })
322
                }
323
        }, AppName(opt.appName))
324
325
        if len(fs) == 1 {
326
                select {
327
                case r := <-chFails:
328
                        if _, ok := r.result.(CancelledError); ok {
329
                                _ = nf.Cancel()
330
                        } else {
331
                                _ = nf.Reject(newNoMatchedError1(r.result))
332
                        }
333
                case r := <-chDones:
334
                        if predicate(r.result) {
335
                                _ = nf.Resolve(r.result)
336
                        } else {
337
                                _ = nf.Reject(newNoMatchedError1(r.result))
338
                        }
339
                }
340
        } else {
341
                Go(func() {
342
                        defer func() {
343
                                if e := recover(); e != nil {
344
                                        _ = nf.Reject(newErrorWithStacks(e))
345
                                }
346
                        }()
347
348
                        j := 0
349
                        for {
350
                                select {
351
                                case r := <-chFails:
352
                                        rs[r.i] = getError(r.result)
353
                                case r := <-chDones:
354
                                        if predicate(r.result) {
355
                                                // try to cancel other futures
356
                                                for _, f := range fs {
357
                                                        _ = f.Cancel()
358
                                                }
359
360
                                                // close the channel for avoid the sender be blocked
361
                                                closeChan := func(c chan anyPromiseResult) {
362
                                                        defer func() { _ = recover() }()
363
                                                        close(c)
364
                                                }
365
                                                closeChan(chDones)
366
                                                closeChan(chFails)
367
368
                                                // resolve the future and return result
369
                                                _ = nf.Resolve(r.result)
370
                                                return
371
                                        } else {
372
                                                rs[r.i] = r.result
373
                                        }
374
                                }
375
376
                                if j++; j == len(fs) {
377
                                        m := 0
378
                                        for _, r := range rs {
379
                                                switch val := r.(type) {
380
                                                case CancelledError:
381
                                                default:
382
                                                        m++
383
                                                        _ = val
384
                                                }
385
                                        }
386
                                        if m > 0 {
387
                                                _ = nf.Reject(newNoMatchedError(rs))
388
                                        } else {
389
                                                _ = nf.Cancel()
390
                                        }
391
                                        break
392
                                }
393
                        }
394
                }, AppName(opt.appName))
395
        }
396
        return nf.Future
397
}
func @341:6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

341
func() {
342
                        defer func() {
343
                                if e := recover(); e != nil {
344
                                        _ = nf.Reject(newErrorWithStacks(e))
345
                                }
346
                        }()
347
348
                        j := 0
349
                        for {
350
                                select {
351
                                case r := <-chFails:
352
                                        rs[r.i] = getError(r.result)
353
                                case r := <-chDones:
354
                                        if predicate(r.result) {
355
                                                // try to cancel other futures
356
                                                for _, f := range fs {
357
                                                        _ = f.Cancel()
358
                                                }
359
360
                                                // close the channel for avoid the sender be blocked
361
                                                closeChan := func(c chan anyPromiseResult) {
362
                                                        defer func() { _ = recover() }()
363
                                                        close(c)
364
                                                }
365
                                                closeChan(chDones)
366
                                                closeChan(chFails)
367
368
                                                // resolve the future and return result
369
                                                _ = nf.Resolve(r.result)
370
                                                return
371
                                        } else {
372
                                                rs[r.i] = r.result
373
                                        }
374
                                }
375
376
                                if j++; j == len(fs) {
377
                                        m := 0
378
                                        for _, r := range rs {
379
                                                switch val := r.(type) {
380
                                                case CancelledError:
381
                                                default:
382
                                                        m++
383
                                                        _ = val
384
                                                }
385
                                        }
386
                                        if m > 0 {
387
                                                _ = nf.Reject(newNoMatchedError(rs))
388
                                        } else {
389
                                                _ = nf.Cancel()
390
                                        }
391
                                        break
392
                                }
393
                        }
394
                }
func WhenAll
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

403
func WhenAll(acts ...any) (fu *Future) {
404
        p := NewPromise()
405
        fu = p.Future
406
407
        opts := make([]utils.OptionExtender, 0, len(acts))
408
        for i, act := range acts {
409
                if opt, ok := act.(utils.OptionExtender); ok {
410
                        opts = append(opts, opt)
411
                        acts = append(acts[:i], acts[i+1:]...)
412
                }
413
        }
414
        opt := utils.ApplyOptions[candyOption](opts...)
415
        p.AppName = opt.appName
416
        if len(acts) == 0 {
417
                _ = p.Resolve([]any{})
418
                return
419
        }
420
421
        fs := make([]*Future, len(acts))
422
        for i, act := range acts {
423
                fs[i] = Promise(act, true, opts...)
424
        }
425
        fu = whenAllFuture(fs, opts...)
426
        return
427
}
func AggregateError.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

46
func (e *AggregateError) Error() string {
47
        if e.InnerErrs == nil {
48
                return e.s
49
        } else {
50
                buf := bytes.NewBufferString(e.s)
51
                buf.WriteString("\n\n")
52
                for i, ie := range e.InnerErrs {
53
                        if ie == nil {
54
                                continue
55
                        }
56
                        buf.WriteString("error appears in Future ")
57
                        buf.WriteString(strconv.Itoa(i))
58
                        buf.WriteString(": ")
59
                        buf.WriteString(ie.Error())
60
                        buf.WriteString("\n")
61
                }
62
                buf.WriteString("\n")
63
                return buf.String()
64
        }
65
}
func newErrorWithStacks
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

71
func newErrorWithStacks(i any) (e error) {
72
        err := getError(i)
73
        buf := bytes.NewBufferString(err.Error())
74
        buf.WriteString("\n")
75
76
        pcs := make([]uintptr, 50)
77
        num := runtime.Callers(2, pcs)
78
        for _, v := range pcs[0:num] {
79
                fun := runtime.FuncForPC(v)
80
                file, line := fun.FileLine(v)
81
                name := fun.Name()
82
                writeStrings(buf, []string{name, " ", file, ":", strconv.Itoa(line), "\n"})
83
        }
84
        return errors.New(buf.String())
85
}
func whenAllFuture
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

434
func whenAllFuture(fs []*Future, opts ...utils.OptionExtender) *Future {
435
        opt := utils.ApplyOptions[candyOption](opts...)
436
        wf := NewPromise()
437
        wf.AppName = opt.appName
438
        rs := make([]any, len(fs))
439
440
        if len(fs) == 0 {
441
                _ = wf.Resolve([]any{})
442
        } else {
443
                n := int32(len(fs))
444
                cancelOthers := func(j int) {
445
                        for k, f1 := range fs {
446
                                if k != j {
447
                                        _ = f1.Cancel()
448
                                }
449
                        }
450
                }
451
452
                Go(func() {
453
                        isCancelled := int32(0)
454
                        for i, f := range fs {
455
                                j := i
456
457
                                f.OnSuccess(func(v any) {
458
                                        rs[j] = v
459
                                        if atomic.AddInt32(&n, -1) == 0 {
460
                                                _ = wf.Resolve(rs)
461
                                        }
462
                                }).OnFailure(func(v any) {
463
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
464
                                                // try to cancel all futures
465
                                                cancelOthers(j)
466
467
                                                // errs := make([]error, 0, 1)
468
                                                // errs = append(errs, v.(error))
469
                                                e := newAggregateError1("error appears in WhenAll:", v)
470
                                                _ = wf.Reject(e)
471
                                        }
472
                                }).OnCancel(func() {
473
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
474
                                                // try to cancel all futures
475
                                                cancelOthers(j)
476
477
                                                _ = wf.Cancel()
478
                                        }
479
                                })
480
                        }
481
                }, AppName(opt.appName))
482
        }
483
484
        return wf.Future
485
}
func @233:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

233
func(o *NewPoolOption) {
234
                o.ApplyTimeout = in.ApplyTimeout
235
                o.ExpiryDuration = in.PoolOption.ExpiryDuration
236
                o.PreAlloc = in.PreAlloc
237
                o.MaxBlockingTasks = in.MaxBlockingTasks
238
                o.Nonblocking = in.Nonblocking
239
                o.PanicHandler = in.PanicHandler
240
                o.Logger = in.Logger
241
                o.DisablePurge = in.DisablePurge
242
        }
func Future.GetOrTimeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

136
func (f *Future) GetOrTimeout(mm uint) (val any, err error, timout bool) {
137
        if mm == 0 {
138
                mm = 10
139
        } else {
140
                mm = mm * 1000 * 1000
141
        }
142
143
        select {
144
        case <-time.After((time.Duration)(mm) * time.Nanosecond):
145
                return nil, nil, true
146
        case <-f.final:
147
                r, err := getFutureReturnVal(f.loadResult())
148
                return r, err, false
149
        }
150
}
func WrapFuture
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

253
func WrapFuture(value any, opts ...utils.OptionExtender) *Future {
254
        opt := utils.ApplyOptions[candyOption](opts...)
255
        p := NewPromise()
256
        p.AppName = opt.appName
257
        if e, ok := value.(error); !ok {
258
                _ = p.Resolve(value)
259
        } else {
260
                _ = p.Reject(e)
261
        }
262
263
        return p.Future
264
}
func showRoutine
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/types.go:

77
func showRoutine(appName string) (r []string) {
78
        locker.RLock()
79
        defer locker.RUnlock()
80
        r = make([]string, 0, len(routines[appName]))
81
        for n, c := range routines[appName] {
82
                r = append(r, n+":"+strconv.Itoa(c))
83
        }
84
        return
85
}
func Future.SetTimeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

99
func (f *Future) SetTimeout(mm int) *Future {
100
        if mm == 0 {
101
                mm = 10
102
        } else {
103
                mm = mm * 1000 * 1000
104
        }
105
106
        Go(func() {
107
                <-time.After((time.Duration)(mm) * time.Nanosecond)
108
                _ = f.Cancel()
109
        }, AppName(f.AppName))
110
        return f
111
}
func @452:6
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

452
func() {
453
                        isCancelled := int32(0)
454
                        for i, f := range fs {
455
                                j := i
456
457
                                f.OnSuccess(func(v any) {
458
                                        rs[j] = v
459
                                        if atomic.AddInt32(&n, -1) == 0 {
460
                                                _ = wf.Resolve(rs)
461
                                        }
462
                                }).OnFailure(func(v any) {
463
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
464
                                                // try to cancel all futures
465
                                                cancelOthers(j)
466
467
                                                // errs := make([]error, 0, 1)
468
                                                // errs = append(errs, v.(error))
469
                                                e := newAggregateError1("error appears in WhenAll:", v)
470
                                                _ = wf.Reject(e)
471
                                        }
472
                                }).OnCancel(func() {
473
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
474
                                                // try to cancel all futures
475
                                                cancelOthers(j)
476
477
                                                _ = wf.Cancel()
478
                                        }
479
                                })
480
                        }
481
                }
func @462:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

462
func(v any) {
463
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
464
                                                // try to cancel all futures
465
                                                cancelOthers(j)
466
467
                                                // errs := make([]error, 0, 1)
468
                                                // errs = append(errs, v.(error))
469
                                                e := newAggregateError1("error appears in WhenAll:", v)
470
                                                _ = wf.Reject(e)
471
                                        }
472
                                }
func NoMatchedError.HasError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

23
func (e *NoMatchedError) HasError() bool {
24
        for _, ie := range e.Results {
25
                if _, ok1 := ie.(error); ok1 {
26
                        return true
27
                }
28
        }
29
        return false
30
}
func Loopc
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

156
func Loopc(ctx context.Context, task any, opts ...utils.OptionExtender) {
157
        opt := utils.ApplyOptions[candyOption](opts...)
158
        allocate(opt.appName, 1, &NewPoolOption{ApplyTimeout: -1}, ignoreRecycled())
159
        exec := func() {
160
                defer func() {
161
                        release(opt.appName, nil, ignoreRecycled())
162
                        if opt.wg != nil {
163
                                opt.wg.Done()
164
                        }
165
                }()
166
                select {
167
                case <-ctx.Done():
168
                case <-wrapPromise(task, false, opts...).
169
                        OnFailure(func(v any) {
170
                                if opt.ch == nil {
171
                                        log.Printf("[Gofusion] %s catches an error in routine.Loopc function: \n"+
172
                                                "error: %s\nfunc: %s\nfunc signature: %T",
173
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
174
                                }
175
                        }).
176
                        OnComplete(func(v any) {
177
                                if opt.ch != nil {
178
                                        opt.ch <- v
179
                                }
180
                        }).
181
                        GetChan():
182
                }
183
        }
184
185
        go exec()
186
}
func @472:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

472
func() {
473
                                        if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
474
                                                // try to cancel all futures
475
                                                cancelOthers(j)
476
477
                                                _ = wf.Cancel()
478
                                        }
479
                                }
func @160:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

160
func() {
161
                        release(opt.appName, nil, ignoreRecycled())
162
                        if opt.wg != nil {
163
                                opt.wg.Done()
164
                        }
165
                }
func pipe.getPipe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

28
func (p *pipe) getPipe(isResolved bool) (func(v any) *Future, *promise) {
29
        if isResolved {
30
                return p.pipeDoneTask, p.pipePromise
31
        } else {
32
                return p.pipeFailTask, p.pipePromise
33
        }
34
}
func @457:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

457
func(v any) {
458
                                        rs[j] = v
459
                                        if atomic.AddInt32(&n, -1) == 0 {
460
                                                _ = wf.Resolve(rs)
461
                                        }
462
                                }
func startPipe
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

179
func startPipe(r *Result, pipeTask func(v any) *Future, pipePromise *promise) {
180
        if pipeTask != nil {
181
                f := pipeTask(r.Result)
182
                f.OnSuccess(func(v any) {
183
                        _ = pipePromise.Resolve(v)
184
                }).OnFailure(func(v any) {
185
                        _ = pipePromise.Reject(getError(v))
186
                })
187
        }
188
189
}
func @309:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

309
func() {
310
                for i, f := range fs {
311
                        k := i
312
                        f.OnSuccess(func(v any) {
313
                                defer func() { _ = recover() }()
314
                                chDones <- anyPromiseResult{result: v, i: k}
315
                        }).OnFailure(func(v any) {
316
                                defer func() { _ = recover() }()
317
                                chFails <- anyPromiseResult{result: v, i: k}
318
                        }).OnCancel(func() {
319
                                defer func() { _ = recover() }()
320
                                chFails <- anyPromiseResult{result: ErrCancelled, i: k}
321
                        })
322
                }
323
        }
func @326:8
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

326
func() {
327
                                        for _, pipe := range v.pipes {
328
                                                pipeTask, pipePromise := pipe.getPipe(r.Typ == ResultSuccess)
329
                                                startPipe(r, pipeTask, pipePromise)
330
                                        }
331
                                }
func @210:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

210
func() {
211
                                        if e := recover(); e != nil {
212
                                                err := newErrorWithStacks(e)
213
                                                fmt.Println("error happens:\n ", err)
214
                                        }
215
                                }
func @444:19
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

444
func(j int) {
445
                        for k, f1 := range fs {
446
                                if k != j {
447
                                        _ = f1.Cancel()
448
                                }
449
                        }
450
                }
func @107:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

107
func(canceller Canceller, a ...any) (any, error) { e := v(canceller); return nil, e }
func Future.OnSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

162
func (f *Future) OnSuccess(callback func(v any)) *Future {
163
        f.addCallback(callback, CallbackDone)
164
        return f
165
}
func promise.OnSuccess
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

69
func (p *promise) OnSuccess(callback func(v any)) *promise {
70
        p.Future.OnSuccess(callback)
71
        return p
72
}
func @209:4
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

209
func() {
210
                                defer func() {
211
                                        if e := recover(); e != nil {
212
                                                err := newErrorWithStacks(e)
213
                                                fmt.Println("error happens:\n ", err)
214
                                        }
215
                                }()
216
                                f()
217
                        }
func @312:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

312
func(v any) {
313
                                defer func() { _ = recover() }()
314
                                chDones <- anyPromiseResult{result: v, i: k}
315
                        }
func @106:5
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

106
func() {
107
                <-time.After((time.Duration)(mm) * time.Nanosecond)
108
                _ = f.Cancel()
109
        }
func promise.OnComplete
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

87
func (p *promise) OnComplete(callback func(v any)) *promise {
88
        p.Future.OnComplete(callback)
89
        return p
90
}
func promise.OnFailure
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

77
func (p *promise) OnFailure(callback func(v any)) *promise {
78
        p.Future.OnFailure(callback)
79
        return p
80
}
func promise.OnCancel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

94
func (p *promise) OnCancel(callback func()) *promise {
95
        p.Future.OnCancel(callback)
96
        return p
97
}
func @159:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

159
func() {
160
                defer func() {
161
                        release(opt.appName, nil, ignoreRecycled())
162
                        if opt.wg != nil {
163
                                opt.wg.Done()
164
                        }
165
                }()
166
                select {
167
                case <-ctx.Done():
168
                case <-wrapPromise(task, false, opts...).
169
                        OnFailure(func(v any) {
170
                                if opt.ch == nil {
171
                                        log.Printf("[Gofusion] %s catches an error in routine.Loopc function: \n"+
172
                                                "error: %s\nfunc: %s\nfunc signature: %T",
173
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
174
                                }
175
                        }).
176
                        OnComplete(func(v any) {
177
                                if opt.ch != nil {
178
                                        opt.ch <- v
179
                                }
180
                        }).
181
                        GetChan():
182
                }
183
        }
func @221:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

221
func() (r any, err error) {
222
                                        r, err = c(v)
223
                                        return
224
                                }
func @361:20
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

361
func(c chan anyPromiseResult) {
362
                                                        defer func() { _ = recover() }()
363
                                                        close(c)
364
                                                }
func writeStrings
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

173
func writeStrings(buf *bytes.Buffer, strings []string) {
174
        for _, s := range strings {
175
                buf.WriteString(s)
176
        }
177
}
func pool.ReleaseTimeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

52
func (p *pool) ReleaseTimeout(timeout time.Duration, opts ...utils.OptionExtender) error {
53
        defer release(p.appName, p, opts...)
54
        return p.pool.ReleaseTimeout(timeout)
55
}
func @234:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

234
func() (r any, err error) {
235
                                        r, err = c()
236
                                        return
237
                                }
func @315:17
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

315
func(v any) {
316
                                defer func() { _ = recover() }()
317
                                chFails <- anyPromiseResult{result: v, i: k}
318
                        }
func @169:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

169
func(v any) {
170
                                if opt.ch == nil {
171
                                        log.Printf("[Gofusion] %s catches an error in routine.Loopc function: \n"+
172
                                                "error: %s\nfunc: %s\nfunc signature: %T",
173
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
174
                                }
175
                        }
func @176:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

176
func(v any) {
177
                                if opt.ch != nil {
178
                                        opt.ch <- v
179
                                }
180
                        }
func @104:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

104
func(canceller Canceller, a ...any) (any, error) { v(canceller); return nil, nil }
func @318:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

318
func() {
319
                                defer func() { _ = recover() }()
320
                                chFails <- anyPromiseResult{result: ErrCancelled, i: k}
321
                        }
func @342:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

342
func() {
343
                                if e := recover(); e != nil {
344
                                        _ = nf.Reject(newErrorWithStacks(e))
345
                                }
346
                        }
func @139:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

139
func(v any) {
140
                                if opt.ch == nil {
141
                                        log.Printf("[Gofusion] %s catches an error in routine.Loop function: \n"+
142
                                                "error: %s\nfunc: %s\nfunc signature: %T",
143
                                                config.ComponentGoroutinePool, v, utils.GetFuncName(task), task)
144
                                }
145
                        }
func @202:13
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

202
func(v any) {
203
                        if opt.ch == nil {
204
                                log.Printf("[Gofusion] %s catches an error in routine.Loop function: \n"+
205
                                        "error: %s\nfunc: %s\nfunc signature: %T",
206
                                        config.ComponentGoroutinePool, v, utils.GetFuncName(fn), fn)
207
                        }
208
                }
func @228:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

228
func() {
229
                                        c()
230
                                }
func @110:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

110
func(canceller Canceller, a ...any) (any, error) { return v(canceller) }
func @182:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

182
func(v any) {
183
                        _ = pipePromise.Resolve(v)
184
                }
func canceller.Cancel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

51
func (c *canceller) Cancel() {
52
        _ = c.f.Cancel()
53
}
func pool.Running
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

43
func (p *pool) Running() int   { return p.pool.Running() }
func pool.Free
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

44
func (p *pool) Free() int      { return p.pool.Free() }
func pool.Waiting
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

45
func (p *pool) Waiting() int   { return p.pool.Waiting() }
func pool.Cap
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

46
func (p *pool) Cap() int       { return p.pool.Cap() }
func pool.IsClosed
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

47
func (p *pool) IsClosed() bool { return p.pool.IsClosed() }
func @184:16
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

184
func(v any) {
185
                        _ = pipePromise.Reject(getError(v))
186
                }
func @233:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

233
func(v any) *Future {
234
                                return start(func() (r any, err error) {
235
                                        r, err = c()
236
                                        return
237
                                }, true)
238
                        }
func @101:10
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

101
func(a ...any) (any, error) { return v() }
func @227:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

227
func(v any) *Future {
228
                                return start(func() {
229
                                        c()
230
                                }, true)
231
                        }
func @220:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

220
func(v any) *Future {
221
                                return start(func() (r any, err error) {
222
                                        r, err = c(v)
223
                                        return
224
                                }, true)
225
                        }
func ignoreMutex
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

101
func ignoreMutex() utils.OptionFunc[internalOption] {
102
        return func(o *internalOption) {
103
                o.ignoreMutex = true
104
        }
105
}
func @102:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

102
func(o *internalOption) {
103
                o.ignoreMutex = true
104
        }
func @215:18
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

215
func() {
216
                                        c(v)
217
                                }
func newAggregateError1
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

67
func newAggregateError1(s string, e any) *AggregateError {
68
        return &AggregateError{newErrorWithStacks(s).Error(), []error{getError(e)}}
69
}
func @214:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

214
func(v any) *Future {
215
                                return start(func() {
216
                                        c(v)
217
                                }, true)
218
                        }
func newNoMatchedError1
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

36
func newNoMatchedError1(e any) *NoMatchedError {
37
        return &NoMatchedError{[]any{e}}
38
}
func Timeout
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

220
func Timeout(t time.Duration) utils.OptionFunc[NewPoolOption] {
221
        return func(o *NewPoolOption) {
222
                o.ApplyTimeout = t
223
        }
224
}
func @221:9
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

221
func(o *NewPoolOption) {
222
                o.ApplyTimeout = t
223
        }
func newNoMatchedError
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

32
func newNoMatchedError(results []any) *NoMatchedError {
33
        return &NoMatchedError{results}
34
}
func @210:12
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

210
func(v any) *Future {
211
                                return c()
212
                        }
func Options
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/pool.go:

232
func Options(in *NewPoolOption) utils.OptionFunc[NewPoolOption] {
233
        return func(o *NewPoolOption) {
234
                o.ApplyTimeout = in.ApplyTimeout
235
                o.ExpiryDuration = in.PoolOption.ExpiryDuration
236
                o.PreAlloc = in.PreAlloc
237
                o.MaxBlockingTasks = in.MaxBlockingTasks
238
                o.Nonblocking = in.Nonblocking
239
                o.PanicHandler = in.PanicHandler
240
                o.Logger = in.Logger
241
                o.DisablePurge = in.DisablePurge
242
        }
243
}
func WhenAny
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

270
func WhenAny(acts ...any) *Future {
271
        return WhenAnyMatched(nil, acts...)
272
}
func CancelledError.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

16
func (e *CancelledError) Error() string {
17
        return "Task be cancelled"
18
}
func promise.Cancel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/promise.go:

50
func (p *promise) Cancel() (e error) {
51
        return p.Future.Cancel()
52
}
func @286:15
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

286
func(v any) bool { return true }
func NoMatchedError.Error
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy_utils.go:

19
func (e *NoMatchedError) Error() string {
20
        return "No matched future"
21
}
func Future.Cancel
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

155
func (f *Future) Cancel() (e error) {
156
        return f.setResult(&Result{ErrCancelled, ResultCancelled})
157
}
func @118:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

118
func() {
119
                c <- f.loadResult()
120
        }
func @362:14
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

362
func() { _ = recover() }
func Future.Canceller
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

82
func (f *Future) Canceller() Canceller {
83
        return &canceller{f}
84
}
func canceller.IsCancelled
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/future.go:

56
func (c *canceller) IsCancelled() (r bool) {
57
        return c.f.IsCancelled()
58
}
func @313:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

313
func() { _ = recover() }
func @316:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

316
func() { _ = recover() }
func @319:11
Back

In /Users/windawings/gopath/src/github.com/wfusion/gofusion/routine/candy.go:

319
func() { _ = recover() }
Report Total
59.8%